Downloads containing ab23btl12.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Anniversary Bash 23 levels Jazz2Online Multiple N/A Download file

File preview

#include "MLLE-Include-1.5w.asc" ///@MLLE-Generated
#pragma require "ab23btl12.j2l" ///@MLLE-Generated
#include "SEfirework-mlle.asc" ///@MLLE-Generated
#pragma require "SEfirework-mlle.asc" ///@MLLE-Generated
class CustomWeaponHook : se::DefaultWeaponHook {
	bool drawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) override {
		int x, y;
		STRING::Size font;
		string text;
		const jjWEAPON@ weapon = jjWeapons[player.currWeapon];
		if (jjSubscreenWidth > 400) {
			x = jjSubscreenWidth - 88;
			y = jjSubscreenHeight - 14;
			font = STRING::MEDIUM;
		} else {
			x = jjSubscreenWidth - 48;
			y = jjSubscreenHeight - 9;
			font = STRING::SMALL;
		}
		if (weapon.infinite || weapon.replacedByShield && player.shieldTime > 0) {
			text = "x^";
		} else {
			int ammo = player.ammo[WEAPON::CURRENT];
			text = "x" + (ammo > 0 ? ammo : 0);
		}
		drawAmmoSprite(canvas, x, y, getWeaponAnimation(player.currWeapon, player.powerup[WEAPON::CURRENT]));
		canvas.drawString(x + 8, y, text, font);
		return true;
	}
}
array<int> lastFired(jjLocalPlayerCount);
array<int> lenientLastFired(jjLocalPlayerCount);
array<bool> missileFired(jjLocalPlayerCount);
array<bool> selectPressed(jjLocalPlayerCount);
array<bool> tongueUsed(jjLocalPlayerCount);
bool canFire(const jjPLAYER@ player) {
	switch (jjWeapons[player.currWeapon].style) {
		case WEAPON::MISSILE:
			return !missileFired[player.localPlayerID];
		case WEAPON::POPCORN:
			return jjGameTicks - lenientLastFired[player.localPlayerID] >= 6;
		case WEAPON::CAPPED:
			return jjGameTicks - lastFired[player.localPlayerID] >= player.fastfire;
	}
	return jjGameTicks - lenientLastFired[player.localPlayerID] >= player.fastfire;
}
void processFiring(const jjPLAYER@ player) {
	if (jjWeapons[player.currWeapon].style == WEAPON::MISSILE)
		missileFired[player.localPlayerID] = true;
	lastFired[player.localPlayerID] = jjGameTicks;
	lenientLastFired[player.localPlayerID] = jjGameTicks;
}
void processNotFiring(const jjPLAYER@ player) {
	missileFired[player.localPlayerID] = false;
	lenientLastFired[player.localPlayerID] = -252000;
}
void cycleWeapon(jjPLAYER@ player) {
	auto initial = player.currWeapon;
	do {
		player.currWeapon = player.currWeapon % 9 + 1;
	} while (player.currWeapon != initial && getRealAmmo(player, WEAPON::CURRENT) == 0);
}
jjANIMATION@ getWeaponAnimation(int weapon, bool powerup) {
	int modifier = powerup ? 1 : 0;
	switch (weapon) {
		case WEAPON::BLASTER:
			return jjAnimations[powerup ? jjAnimSets[ANIM::AMMO] + 18 : jjAnimSets[ANIM::PICKUPS] + 29];
		case WEAPON::BOUNCER:
			return jjAnimations[jjAnimSets[ANIM::AMMO] + 25 - modifier];
		case WEAPON::ICE:
			return jjAnimations[jjAnimSets[ANIM::CUSTOM[0]] + modifier];
		case WEAPON::SEEKER:
			return jjAnimations[jjAnimSets[ANIM::AMMO] + 34 - modifier];
		case WEAPON::RF:
			return jjAnimations[jjAnimSets[ANIM::AMMO] + 49 - modifier];
		case WEAPON::TOASTER:
			return jjAnimations[jjAnimSets[ANIM::AMMO] + 57 - modifier];
		case WEAPON::TNT:
			return jjAnimations[jjAnimSets[ANIM::AMMO] + 59];
		case WEAPON::GUN8:
			return jjAnimations[jjAnimSets[ANIM::AMMO] + 62 - modifier];
		case WEAPON::GUN9:
			return jjAnimations[jjAnimSets[ANIM::AMMO] + 68 - modifier];
	}
	return null;
}
int getWeaponEventID(int weapon, bool powerup, bool &out pepper) {
	auto spread = jjWeapons[weapon].spread;
	if (spread == SPREAD::PEPPERSPRAY || spread == SPREAD::GUN8 && !jjAllowsFireball) {
		pepper = true;
		return OBJECT::BULLET;
	}
	pepper = false;
	int modifier = powerup ? 8 : 0;
	switch (weapon) {
		case WEAPON::BLASTER:
			return OBJECT::BLASTERBULLET + modifier;
		case WEAPON::BOUNCER:
			return OBJECT::BOUNCERBULLET + modifier;
		case WEAPON::ICE:
			return OBJECT::ICEBULLET + modifier;
		case WEAPON::SEEKER:
			return OBJECT::SEEKERBULLET + modifier;
		case WEAPON::RF:
			return OBJECT::RFBULLET + modifier;
		case WEAPON::TOASTER:
			return OBJECT::TOASTERBULLET + modifier;
		case WEAPON::TNT:
			return OBJECT::TNT;
		case WEAPON::GUN8:
			return OBJECT::FIREBALLBULLET + modifier;
		case WEAPON::GUN9:
			return OBJECT::ELECTROBULLET + modifier;
	}
	return 0;
}
void drawAmmoSprite(jjCANVAS@ canvas, int x, int y, const jjANIMATION@ anim) {
	if (anim !is null)
		canvas.drawSpriteFromCurFrame(x, y, anim + (::jjGameTicks >> 2) % anim.frameCount);
}
void fireBullet(const jjPLAYER@ player, int angle, float x, float y) {
	bool pepper;
	auto eventID = getWeaponEventID(player.currWeapon, player.powerup[WEAPON::CURRENT], pepper);
	int id = jjAddObject(eventID, x, y, player.playerID, CREATOR::PLAYER, pepper ? BEHAVIOR::PEPPERBULLET : BEHAVIOR::DEFAULT);
	if (id > 0) {
		auto@ obj = jjObjects[id];
		if (pepper) {
			bool powerup = jjStrongPowerups && player.powerup[WEAPON::CURRENT];
			obj.playerHandling = HANDLING::PLAYERBULLET;
			obj.determineCurAnim(ANIM::AMMO, powerup ? 10 : 9);
			obj.determineCurFrame();
			obj.animSpeed = player.powerup[WEAPON::CURRENT] ? 2 : 1;
			obj.var[3] = 8;
			obj.xSpeed = 4.f;
			if (powerup) {
				obj.lightType = LIGHT::POINT2;
				obj.state = STATE::FLY;
				obj.var[6] = obj.var[6] | 8;
			}
		}
		float speed = obj.xSpeed;
		float acc = obj.xAcc;
		obj.xSpeed = jjCos(angle << 7) * speed;
		obj.ySpeed -= jjSin(angle << 7) * speed;
		obj.xAcc = jjCos(angle << 7) * acc;
		obj.yAcc -= jjSin(angle << 7) * acc;
		obj.direction = angle < 2 ? 1 : angle > 2 ? -1 : 0;
	}
}
int getRealAmmo(const jjPLAYER@ player, int weapon) {
	if (weapon == WEAPON::CURRENT)
		weapon = player.currWeapon;
	auto@ preset = jjWeapons[weapon];
	int multiplier = preset.multiplier;
	preset.multiplier = 1;
	int result = player.ammo[weapon];
	preset.multiplier = multiplier;
	return result;
}
void decrementRealAmmo(jjPLAYER@ player, int weapon) {
	if (weapon == WEAPON::CURRENT)
		weapon = player.currWeapon;
	auto@ preset = jjWeapons[weapon];
	int multiplier = preset.multiplier;
	preset.multiplier = 1;
	player.ammo[weapon] = player.ammo[weapon] - 1;
	preset.multiplier = multiplier;
}
void coinMorph(jjOBJ@ obj) {
	if (obj.state == STATE::DEACTIVATE) {
		obj.deactivate();
		return;
	}
	if (obj.state == STATE::START) {
		int x = int(obj.xOrg) >>> 5;
		int y = int(obj.yOrg) >>> 5;
		if (jjParameterGet(x, y, 17, 1) == 0) {
			obj.delete();
			return;
		}
		obj.state = STATE::STILL;
		obj.var[0] = jjParameterGet(x, y, 8, 8);
		obj.var[1] = jjParameterGet(x, y, 0, 8);
		obj.var[2] = jjParameterGet(x, y, 16, 1);
		obj.var[3] = jjParameterGet(x, y, 18, 1);
		obj.xPos -= 16.f;
		obj.yPos -= 16.f;
		obj.putOnGround(true);
		return;
	}
	auto@ bunny = jjAnimations[obj.curAnim];
	auto@ booth = jjAnimations[obj.special];
	obj.counter++;
	if (obj.counter & 7 == 0) {
		obj.frameID++;
		if (obj.frameID >= int(bunny.frameCount))
			obj.frameID = 0;
		obj.determineCurFrame();
	}
	jjDrawSpriteFromCurFrame(obj.xPos - 1.f, obj.yPos + 3.f, booth + (obj.counter >> 3) % booth.frameCount, obj.direction, SPRITE::PALSHIFT, 16);
	jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame + bunny.frameCount, obj.direction);
	jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, 40);
	if (obj.var[0] != 0) {
		jjTEXTAPPEARANCE style(STRING::BOUNCE);
		style.align = STRING::CENTER;
		jjDrawString(obj.xPos - 4.f, obj.yPos - 12.f, formatInt(obj.var[0]), STRING::SMALL, style, 0, SPRITE::PALSHIFT, 224);
	}
	for (int i = 0; i < jjLocalPlayerCount; i++) {
		auto@ player = jjLocalPlayers[i];
		float dx = player.xPos - obj.xPos;
		float dy = player.yPos - obj.yPos;
		if (dx * dx + dy * dy < 1024.f && player.charCurr != CHAR::BIRD && player.testForCoins(obj.var[0])) {
			player.morphTo(CHAR::BIRD);
			jjSample(player.xPos, player.yPos, SOUND::COMMON_BUBBLGN1);
		}
	}
}
bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
	return MLLE::WeaponHook.drawAmmo(player, canvas);
}
void onLevelLoad() {
	@MLLE::WeaponHook = CustomWeaponHook();
	MLLE::Setup(array<MLLEWeaponApply@> = {null, null, se::FireworkMLLEWrapper(), null, null, null, null, null, null});
	jjCharacters[CHAR::FROG].canHurt = true;
	jjCharacters[CHAR::FROG].canRun = true;
	jjCharacters[CHAR::BIRD].canHurt = true;
	jjCharacters[CHAR::BIRD].canRun = true;
	jjObjectPresets[OBJECT::WARP].behavior = coinMorph;
}
void onPlayerInput(jjPLAYER@ player) {
	auto@ weapon = jjWeapons[player.currWeapon];
	auto style = weapon.style;
	if (player.charCurr == CHAR::FROG || player.charCurr == CHAR::BIRD) {
		if (player.keySelect) {
			if (!selectPressed[player.localPlayerID]) {
				selectPressed[player.localPlayerID] = true;
				cycleWeapon(player);
			}
		} else {
			selectPressed[player.localPlayerID] = false;
		}
	}
	if (player.charCurr == CHAR::BIRD) {
		if (player.keyFire) {
			player.keyFire = false;
			if (canFire(player) && player.currWeapon != WEAPON::BLASTER) {
				int anim = player.curAnim - jjAnimSets[ANIM::BIRD];
				if (anim >= 9 && anim != 10 && anim != 19) {
					if (anim != 9)
						player.keyUp = true;
					player.fireBullet();
					processFiring(player);
					if (getRealAmmo(player, WEAPON::CURRENT) == 0 && !weapon.infinite)
						cycleWeapon(player);
				}
			}
		} else {
			processNotFiring(player);
		}
		if (player.keyJump) {
			player.keyFire = true;
			player.keyJump = false;
		}
	}
}
void onPlayer(jjPLAYER@ player) {
	if (player.xSpeed > 6.f)
		player.xSpeed = 6.f;
	if (player.xSpeed < -6.f)
		player.xSpeed = -6.f;
	if (player.charCurr == CHAR::FROG) {
		int anim = player.curAnim - jjAnimSets[ANIM::FROG] + (jjIsTSF ? 0 : 1);
		if (anim >= 8 && anim <= 10 && player.frameID == 6) {
			if (!tongueUsed[player.localPlayerID]) {
				tongueUsed[player.localPlayerID] = true;
				if (player.currWeapon != WEAPON::BLASTER) {
					if (getRealAmmo(player, WEAPON::CURRENT) > 0) {
						decrementRealAmmo(player, WEAPON::CURRENT);
						int angle = anim == 10 ? 2 : player.direction < 0 ? anim - 5 : 9 - anim;
						float x = player.xPos + jjCos(angle << 7) * 76.f + (player.direction < 0 ? 4.f : -4.f);
						float y = player.yPos - jjSin(angle << 7) * 76.f + 8.f;
						jjSTREAM packet;
						packet.push(uint8(player.playerID));
						packet.push(uint8(player.currWeapon));
						packet.push(bool(player.powerup[WEAPON::CURRENT]));
						packet.push(uint(player.ammo[WEAPON::CURRENT]));
						packet.push(uint8(angle));
						packet.push(float(x));
						packet.push(float(y));
						jjSendPacket(packet);
						fireBullet(player, angle, x, y);
					}
					if (getRealAmmo(player, WEAPON::CURRENT) == 0 && !jjWeapons[player.currWeapon].infinite)
						cycleWeapon(player);
				}
			}
		} else {
			tongueUsed[player.localPlayerID] = false;
		}
	} else if (player.charCurr != CHAR::BIRD) {
		player.morphTo(CHAR::FROG);
	}
}
void onReceive(jjSTREAM &in packet, int clientID) {
	jjSTREAM backup = packet;
	uint8 playerID, weapon, angle;
	uint ammo;
	bool powerup;
	float x, y;
	if (!packet.pop(playerID) || !packet.pop(weapon) || !packet.pop(powerup) || !packet.pop(ammo) || !packet.pop(angle) || !packet.pop(x) || !packet.pop(y))
		return;
	if (playerID >= 32 || weapon <= 1 || weapon >= 10 || angle >= 5)
		return;
	auto@ player = jjPlayers[playerID];
	if (jjIsServer && player.clientID != clientID || player.isLocal)
		return;
	if (jjIsServer)
		jjSendPacket(backup, -clientID);
	player.currWeapon = weapon;
	player.powerup[weapon] = powerup;
	player.ammo[weapon] = ammo;
	fireBullet(player, angle, x, y);
}