Downloads containing BossrushV2.j2as

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

File preview

const array<int> TurtleSpriteRecolorOffsets = {6*8, 5*8, 4*8, -2*8};
void onLevelLoad() {
	for (uint i = 0; i < 4; ++i) {
		jjANIMSET@ animSet = jjAnimSets[ANIM::CUSTOM[i]].load(ANIM::TUFBOSS);
		for (uint j = 0; j < 6; ++j) { //animCount
			jjANIMATION@ animation = jjAnimations[animSet.firstAnim + j];
			for (uint k = 0; k < animation.frameCount; ++k) {
				jjANIMFRAME@ frame = jjAnimFrames[animation.firstFrame + k];
				jjPIXELMAP image(frame);
				for (uint x = 0; x < image.width; ++x)
					for (uint y = 0; y < image.height; ++y)
						if (image[x,y] / 8 == 9) //gray
							image[x,y] -= TurtleSpriteRecolorOffsets[i];
				image.save(frame);
			}
		}
	}
	if (jjAnimSets[ANIM::TURTLE] == 0)
		jjAnimSets[ANIM::TURTLE].load(); //want the sounds
	for (uint xTile = 6; xTile < 9; ++xTile)
		for (uint yTile = 6; yTile < 8; ++yTile) {
			jjPIXELMAP oldTile(xTile + yTile*10);
			jjPIXELMAP newTile();
			for (uint xx = 0; xx < 32; ++xx)
				for (uint yy = 0; yy < 32; ++yy)
					newTile[31-yy, xx] = oldTile[xx,yy];
			newTile.save(xTile + yTile*10, true); //rotated!
		}
	jjObjectPresets[OBJECT::GEMBARREL].behavior = Turtle;
	jjObjectPresets[OBJECT::GEMBARREL].energy = 100; //maybe
	jjObjectPresets[OBJECT::GEMBARREL].scriptedCollisions = true;
	jjObjectPresets[OBJECT::GEMBARREL].playerHandling = HANDLING::SPECIAL;
	jjObjectPresets[OBJECT::GEMBARREL].bulletHandling = HANDLING::DETECTBULLET;
	jjObjectPresets[OBJECT::GEMBARREL].animSpeed = 9;
	jjObjectPresets[OBJECT::GEMBARREL].age = 10; //damage that can be taken (in midair) before turning into a shell again
	jjObjectPresets[OBJECT::GEMBARREL].special = 0; //no initial platform
	jjObjectPresets[OBJECT::GEMBARREL].points = 0;
	
	jjObjectPresets[OBJECT::ELECTROBULLET].behavior = Flailerang;
	jjObjectPresets[OBJECT::ELECTROBULLET].killAnim = jjAnimSets[ANIM::AMMO].firstAnim + 6;
	
	jjObjectPresets[OBJECT::BLASTERBULLET].animSpeed = 2; //to give physical attacks less of an advantage
	
	jjObjectPresets[OBJECT::CAKE].behavior = BossHealthMeter;
	jjObjectPresets[OBJECT::CAKE].playerHandling = HANDLING::PARTICLE; //just to be safe
	jjObjectPresets[OBJECT::CAKE].energy = jjObjectPresets[OBJECT::GEMBARREL].energy;
	
	jjObjectPresets[OBJECT::STEADYLIGHT].behavior = CenterOfLevel;
	
	jjObjectPresets[OBJECT::BANANA].behavior = TurtleWood;
	jjObjectPresets[OBJECT::BANANA].playerHandling = HANDLING::PARTICLE;
	jjObjectPresets[OBJECT::BANANA].counterEnd = 96; //how long it has to rise
	jjObjectPresets[OBJECT::BANANA].var[0] = 512; //initial angle
	jjPIXELMAP WoodTiles(9, 0, 15, 96, 5);
	jjPIXELMAP WoodSprite(96, 15);
	jjANIMFRAME@ WoodFrame = jjAnimFrames[jjObjectPresets[OBJECT::BANANA].curFrame];
	for (uint xx = 0; xx < 15; ++xx)
		for (uint yy = 0; yy < 96; ++yy)
			WoodSprite[95-yy, xx] = WoodTiles[xx,yy];
	WoodSprite.save(WoodFrame);
	WoodFrame.hotSpotX = -48;
	WoodFrame.hotSpotY = -2;
	
	jjObjectPresets[OBJECT::APPLE].behavior = BEHAVIOR::INACTIVE;
	//jjObjectPresets[OBJECT::APPLE].playerHandling = HANDLING::PARTICLE;
	//jjObjectPresets[OBJECT::APPLE].curFrame = jjObjectPresets[OBJECT::BANANA].curFrame;
	
	jjObjectPresets[OBJECT::GEMBARREL].deactivates = false;
	jjObjectPresets[OBJECT::BANANA].deactivates = false;
	jjObjectPresets[OBJECT::APPLE].deactivates = false;
	
	jjWeapons[WEAPON::GUN9].infinite = true;
	jjWeapons[WEAPON::GUN9].defaultSample = false;
	jjWeapons[WEAPON::GUN9].style = WEAPON::CAPPED;
	
	jjAnimations[jjAnimSets[ANIM::PICKUPS] + 41] = jjAnimations[jjAnimSets[ANIM::PICKUPS] + 77];//pizza
	
	jjWaterLayer = 6;
}

uint TurtlesDefeated = 0;
void onLevelReload() {
	TurtlesDefeated = 0;
}
bool onDrawScore(jjPLAYER@ play, jjCANVAS@ screen) {
	screen.drawString(0x8000, 30, "" + TurtlesDefeated + "/4", STRING::MEDIUM);
	return true;
}
bool onDrawAmmo(jjPLAYER@ play, jjCANVAS@ screen) { return true; }
void onPlayerInput(jjPLAYER@ play) {
	play.currWeapon = (play.platform == 0) ? WEAPON::BLASTER : WEAPON::GUN9;
}
void onDrawLayer6(jjPLAYER@ play, jjCANVAS@ screen) {
	jjSetWaterLevel(-32, true);
}
void onDrawLayer4(jjPLAYER@ play, jjCANVAS@ screen) {
	jjSetWaterLevel(16000, true);
}

enum TurtleAnims { taTHROW, taCATCH, taSHELL, taFLAILERANG, taSTAND, taWALK };
void startAnimation(jjOBJ@ obj, TurtleAnims animID, bool onGround) {
	obj.determineCurAnim(ANIM::CUSTOM[obj.doesHurt], animID);
	obj.frameID = 0;
	obj.determineCurFrame();
	obj.counterEnd = obj.animSpeed;
	if (onGround) {
		obj.yPos -= 50; //some room to fall
		obj.putOnGround(true);
	}
}
void Turtle(jjOBJ@ obj) {
	if (obj.state == STATE::START) {
		obj.doesHurt = jjParameterGet(int(obj.xOrg / 32), int(obj.yOrg / 32), 0, 3); //color
		@Turtles[obj.doesHurt] = obj;
		obj.state = STATE::DELAYEDSTART;
		obj.counter = jjParameterGet(int(obj.xOrg / 32), int(obj.yOrg / 32), 4, 4) * 70; //delay
		startAnimation(obj, taSHELL, true);
	} else if (obj.age <= 0) { //sustained too much damage
		obj.age = jjObjectPresets[obj.eventID].age;
		obj.state = STATE::TURN;
		obj.ySpeed = -4;
		jjSample(obj.xPos, obj.yPos, SOUND::TURTLE_TURN);
		startAnimation(obj, taSHELL, false);
		obj.xSpeed = -5 * obj.direction;
		deleteWood(obj);
	}
	if (obj.state == STATE::DELAYEDSTART) {
		if (abs(obj.xSpeed) > 0.2f) {
			if (!jjMaskedPixel(int(obj.xPos + obj.xSpeed), int(obj.yPos))) //can move
				obj.xPos += obj.xSpeed;
			else {
				obj.xSpeed = -obj.xSpeed;
				jjSample(obj.xPos, obj.yPos, SOUND::COMMON_IMPACT7);
			}
			if (obj.xSpeed > 0) {
				obj.xSpeed -= 0.1f;
				obj.direction = 1;
			} else {
				obj.xSpeed += 0.1f;
				obj.direction = -1;
			}
			
		}
		if (--obj.counter <= 0) {
			jjSample(obj.xPos, obj.yPos, SOUND::TURTLE_HIDE);
			obj.state = STATE::WAIT;
			obj.counter = 100;
			startAnimation(obj, taSTAND, true);
			obj.direction = (obj.xPos > CENTERX) ? -1 : 1;
		}
	} else if (obj.state == STATE::WAIT) {
		if (--obj.counter <= 0) {
			obj.state = STATE::WALK;
			startAnimation(obj, taWALK, true);
		}
	} else if (obj.state == STATE::WALK) {
		if (abs(obj.xPos - CENTERX) > 3) { //not at center
			if (obj.xPos > CENTERX)
				obj.xPos -= 1.4f;
			else
				obj.xPos += 1.4f;
		} else {
			obj.special = jjAddObject(OBJECT::BANANA, CENTERX, jjLayerHeight[4] * 32); //flying platform
			jjObjects[obj.special].special = obj.objectID; //mutual
			obj.state = STATE::JUMP;
			obj.counter = 200 + (obj.doesHurt * 50);
			startAnimation(obj, taSTAND, true);
			obj.direction = (obj.xPos > jjLocalPlayers[0].xPos) ? -1 : 1;
		}
	} else if (obj.state == STATE::JUMP) {
		if (--obj.counter <= 0) {
			obj.state = STATE::FIRE;
			startAnimation(obj, taTHROW, false);
		}
	} else if (obj.state == STATE::FIRE) {
		if (obj.frameID == 13 && obj.counterEnd == uint(obj.animSpeed)) {
			obj.fireBullet(OBJECT::ELECTROBULLET);
		} else if (obj.frameID == 18 && obj.counterEnd == 1) {
			obj.state = STATE::JUMP;
			obj.counter = 200 + (obj.doesHurt * 50);
			startAnimation(obj, taSTAND, false);
		} else 
			obj.var[2] = jjSampleLooped(obj.xPos, obj.yPos, SOUND::TUFBOSS_SWING, obj.var[2]);
	} else if (obj.state == STATE::TURN) {
		obj.xPos += obj.xSpeed;
		obj.yPos += obj.ySpeed;
		/*if (obj.xSpeed > 0) {
			obj.xSpeed -= 0.1f;
			obj.direction = 1;
		} else {
			obj.xSpeed += 0.1f;
			obj.direction = -1;
		}*/
		obj.ySpeed += 0.2f;
		if (obj.xPos < 60) {
			obj.xPos = 60;
			obj.xSpeed = abs(obj.xSpeed);
			obj.direction = 1;
			jjSample(obj.xPos, obj.yPos, SOUND::COMMON_IMPACT7);
		} else if (obj.xPos > jjLayerWidth[4] * 32 - 60) {
			obj.xPos = jjLayerWidth[4] * 32 - 60;
			obj.xSpeed = -abs(obj.xSpeed);
			obj.direction = -1;
			jjSample(obj.xPos, obj.yPos, SOUND::COMMON_IMPACT7);
		}
		if (obj.yPos > 23*32) {
			obj.state = STATE::DELAYEDSTART;
			obj.counter = 140; //delay
			startAnimation(obj, taSHELL, true);
		}
		jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, jjGameTicks * -16 * obj.direction, obj.direction);
		return;
	}
	if (--obj.counterEnd == 0) {
		obj.counterEnd = obj.animSpeed;
		++obj.frameID;
		obj.frameID %= jjAnimations[obj.curAnim].frameCount;
		obj.determineCurFrame();
	}
	if (!(obj.special != 0 && jjObjects[obj.special].counterEnd == 0)) //wooden platform has finished ascending and has taken over
		obj.draw();
}
void onObjectHit(jjOBJ@ obj, jjOBJ@ bull, jjPLAYER@ play, int force) {
	if (obj.behavior == Turtle) {
		if (bull is null) {
			if (obj.state == STATE::DELAYEDSTART) //in shell
				play.hurt();
			else if (obj.state != STATE::TURN) {
				int oldEnergy = obj.energy;
				play.objectHit(obj, play.getObjectHitForce(obj), HANDLING::ENEMY);
				if (obj.special != 0)
					obj.age -= (oldEnergy - obj.energy);
			}
		} else {
			if (obj.state != STATE::DELAYEDSTART && obj.state != STATE::TURN) {
				obj.energy -= force;
				if (obj.special != 0) {
					if (bull.behavior == Flailerang) //instant defeat!
						obj.age = 0;
					else obj.age -= 1; //incremental
				}
				obj.justHit = 5;
				jjSample(obj.xPos, obj.yPos, SOUND::TURTLE_IDLE2);
				bull.state = STATE::EXPLODE;
			} else {
				jjSample(obj.xPos, obj.yPos, SOUND::TURTLE_HITSHELL);
				obj.xSpeed = bull.xSpeed;
				obj.counter += 30; //stay in shell longer
				if (!bull.ricochet()) //surely always true
					bull.state = STATE::EXPLODE;
			}
		}
		if (obj.energy <= 0) { //still exist, so the energy can be counted, but don't interact with anything
			obj.energy = 0; //to avoid triggering level end too quickly
			obj.bulletHandling = HANDLING::IGNOREBULLET;
			obj.behavior = BEHAVIOR::BEES; //do nothing
			obj.particlePixelExplosion((bull is null) ? 2 : 0);
			++TurtlesDefeated;
			deleteWood(obj);
		}
	}
}
void deleteWood(jjOBJ@ obj) {
	if (obj.special != 0) {
		jjOBJ@ wood = jjObjects[obj.special];
		wood.special = 0;
		obj.special = 0;
		wood.behavior = RabbitWood;
	}
}

array<jjOBJ@> Turtles(4);
void BossHealthMeter(jjOBJ@ obj) {
	if (obj.state == STATE::START) {
		jjLocalPlayers[0].activateBoss();
		jjLocalPlayers[0].boss = obj.objectID;
		obj.state = STATE::WAIT;
	}
	int combinedEnergy = Turtles[0].energy + Turtles[1].energy + Turtles[2].energy + Turtles[3].energy;
	if (combinedEnergy <= 0) {
		jjLocalPlayers[0].activateBoss(false);
		jjNxt("BossrushV2");
		obj.delete(); //don't try to cycle more than once
	} else
		obj.energy = combinedEnergy / 4; //for display
}

float CENTERX;
void CenterOfLevel(jjOBJ@ obj) {
	CENTERX = obj.xOrg;
	obj.behavior = BEHAVIOR::STEADYLIGHT;
}

void orientWoodToward(jjOBJ@ obj, int targetAngle, int turnSpeed, float platSpeed) {
	int currentAngle = obj.var[0];
	if (currentAngle != targetAngle) {
		float angleDifference = abs(((currentAngle + 512 - targetAngle) & 1023) - 512);
		if (angleDifference > 512) angleDifference = abs(angleDifference - 1024);
		if (int(currentAngle + angleDifference) & 1023 == targetAngle)
			currentAngle += turnSpeed;
		else
			currentAngle -= turnSpeed;
		currentAngle &= 1023;
	}
	obj.xSpeed = jjSin(currentAngle) * platSpeed;
	obj.ySpeed = jjCos(currentAngle) * platSpeed;
	obj.var[0] = currentAngle;
	obj.var[1] = targetAngle;
	
	float oldX = obj.xPos, oldY = obj.yPos;
	obj.xPos += obj.xSpeed;
	obj.yPos += obj.ySpeed;
	obj.bePlatform(oldX, oldY);
}
void TurtleWood(jjOBJ@ obj) {
	jjOBJ@ turtle = jjObjects[obj.special];
	
	if (obj.counterEnd > 0) {
		obj.yPos -= 2;
		obj.counterEnd -= 2;
		if (obj.counterEnd == 0) {
		}
		obj.draw();
	} else {
		jjPLAYER@ target = jjLocalPlayers[0];
		const int targetAngle = int(atan2(target.xPos - obj.xPos, target.yPos - obj.yPos) / 6.28f * 1024) & 1023;
		orientWoodToward(obj, targetAngle, turtle.doesHurt + 2, 4);
		
		turtle.xPos = obj.xPos;
		turtle.yPos = obj.yPos - 25;
		turtle.direction = (obj.xSpeed >= 0) ? 1 : -1;
		
		jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, int(obj.xSpeed) * 8);
		jjDrawRotatedSpriteFromCurFrame(turtle.xPos, turtle.yPos, turtle.curFrame, int(obj.xSpeed) * 8, turtle.direction, 1, (turtle.justHit == 0) ? SPRITE::NORMAL : SPRITE::SINGLECOLOR, 15);
	}
}
void RabbitWood(jjOBJ@ obj) {
	if (obj.counterEnd > 0) {
		obj.yPos -= 2;
		obj.counterEnd -= 2;
		if (obj.counterEnd == 0) {
		}
		obj.draw();
	} else {
		jjPLAYER@ play = jjLocalPlayers[0];
		
		if (play.platform != obj.objectID) {
			/*obj.particlePixelExplosion(0);
			obj.clearPlatform();
			obj.delete();
			jjSamplePriority(SOUND::COMMON_COLLAPS);*/
			obj.var[0] = 512; //angle=up
			const float oldY = obj.yPos;
			obj.yPos = oldY + 2;
			obj.xSpeed = jjSin(jjGameTicks * 16) * 3;
			if (play.platform == 0)
				obj.bePlatform(obj.xPos, oldY);
		} else {
			int targetAngle = 256;
			if (play.keyUp) targetAngle = 512;
			else if (play.keyDown) targetAngle = 0;
			else if (play.direction < 0) targetAngle = 768;
			orientWoodToward(obj, targetAngle, (play.keyRun ? 10 : 5), (play.keyRun ? 5.5 : 4));
		}
		jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, int(obj.xSpeed) * 8);
	}
	
}
void onFunction0(jjPLAYER@ play) {
	jjObjects[jjAddObject(OBJECT::BANANA, CENTERX, jjLayerHeight[4] * 32, play.playerID, CREATOR::PLAYER, RabbitWood)].counterEnd -= 2; //flying platform
}

/*void YourWood(jjOBJ@ obj) {
	if (obj.state == STATE::START) {
		obj.counter = jjParameterGet(int(obj.xOrg / 32), int(obj.yOrg / 32), 0, 8) * 4;
	}
	float oldY = obj.yPos;
	obj.yPos = obj.yOrg + jjSin(jjGameTicks * 2 + obj.counter) * 96;
	obj.bePlatform(obj.xPos, oldY);
	obj.draw();
}*/

void Flailerang(jjOBJ@ obj) {
	if (obj.state == STATE::DEACTIVATE) {
		obj.delete();
		return;
	} else if (obj.state == STATE::START) {
		jjSample(obj.xPos, obj.yPos, SOUND::TUFBOSS_RELEASE);
		obj.state = STATE::FLY;
		int angle;
		if (obj.creatorType == CREATOR::OBJECT) {
			jjOBJ@ turtle = jjObjects[obj.creator];
			angle = jjObjects[turtle.special].var[1];
			obj.determineCurAnim(ANIM::CUSTOM[turtle.doesHurt], taFLAILERANG);
			obj.playerHandling = HANDLING::ENEMYBULLET;
		} else {
			angle = jjObjects[jjPlayers[obj.creator].platform].var[1];
			obj.determineCurAnim(ANIM::CUSTOM[0], taFLAILERANG);
			obj.animSpeed = 7; //do more damage than the blaster
		}
		obj.xSpeed = jjSin(angle) * 5;
		obj.ySpeed = jjCos(angle) * 5;
		obj.direction = (obj.xSpeed > 0) ? 1 : -1;
	} else if (obj.state == STATE::EXPLODE) {
		if (obj.creator == CREATOR::PLAYER)
			obj.particlePixelExplosion(16);
		obj.behavior = BEHAVIOR::EXPLOSION;
		obj.curAnim = obj.killAnim;
		obj.playerHandling = HANDLING::EXPLOSION;
		jjSample(obj.xPos, obj.yPos, SOUND::COMMON_METALHIT);
		return;
	}
	obj.xPos += obj.xSpeed;
	obj.yPos += obj.ySpeed;
	obj.frameID = (jjGameTicks >> 2) % jjAnimations[obj.curAnim].frameCount;
	obj.determineCurFrame();
	if (obj.creatorType == CREATOR::OBJECT)
		obj.draw();
	else
		jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, -8); //green
}