Downloads containing cleanSE.j2as

Downloads
Name Author Game Mode Rating
JJ2+ Only: Anniversary Bash 25 CTF Jazz2Online Capture the flag N/A Download file
TSF with JJ2+ Only: Anniversary Bash 22 levels Jazz2Online Multiple N/A Download file
TSF with JJ2+ Only: Anniversary Bash 21 Levels Jazz2Online Multiple N/A Download file
JJ2+ Only: CleanseFeatured Download Seren Capture the flag 8.7 Download file

File preview

#pragma require "Buildsit.j2t"
#pragma require "cleanSE.j2a"
#pragma require "cleanSE.pal"
#pragma require "SEenergyblast.asc"
#include "SEenergyblast.asc"
class float2 {
	float x, y;
	float2() {}
	float2(const float2& other) {
		this = other;
	}
	float2(float x, float y) {
		this.x = x;
		this.y = y;
	}
	float& opIndex(uint index) {
		return index == 0 ? x : y;
	}
	const float& opIndex(uint index) const {
		return index == 0 ? x : y;
	}
	float2& opAddAssign(const float2& rhs) {
		x += rhs.x;
		y += rhs.y;
		return this;
	}
	float2& opSubAssign(const float2& rhs) {
		x -= rhs.x;
		y -= rhs.y;
		return this;
	}
	float2& opMulAssign(float rhs) {
		x *= rhs;
		y *= rhs;
		return this;
	}
	float2& opDivAssign(float rhs) {
		x /= rhs;
		y /= rhs;
		return this;
	}
	bool opEquals(const float2& rhs) const {
		return x == rhs.x && y == rhs.y;
	}
	float2 opNeg() const {
		return float2(-x, -y);
	}
	float2 opAdd(const float2& rhs) const {
		return float2(x + rhs.x, y + rhs.y);
	}
	float2 opSub(const float2& rhs) const {
		return float2(x - rhs.x, y - rhs.y);
	}
	float2 opMul(float rhs) const {
		return float2(x * rhs, y * rhs);
	}
	float2 opMul_r(float lhs) const {
		return float2(lhs * x, lhs * y);
	}
	float2 opDiv(float rhs) const {
		return float2(x / rhs, y / rhs);
	}
}
float dot(const float2& lhs, const float2& rhs) {
	return lhs.x * rhs.x + lhs.y * rhs.y;
}
float abs(const float2& vec) {
	return ::sqrt(dot(vec, vec));
}
class BuzzSaw : jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ obj) override {
		if (obj.state == STATE::START) {
			obj.state = STATE::TURN;
			obj.special = 3 + 2 * jjParameterGet(int(obj.xOrg) >>> 5, int(obj.yOrg) >>> 5, 0, 1);
			bool prev = false;
			for (int i = 0; i <= 1024; i += 2) {
				float sine = jjSin(i);
				float cosine = jjCos(i);
				float x = floor(obj.xPos + sine * 56.f + 0.5f);
				float y = floor(obj.yPos + cosine * 56.f + 0.5f);
				bool cur = jjMaskedPixel(int(x), int(y));
				if (prev && !cur) {
					obj.state = STATE::ROTATE;
					obj.xAcc = x;
					obj.yAcc = y;
					obj.xSpeed = cosine * 4.f;
					obj.ySpeed = -sine * 4.f;
					break;
				}
				prev = cur;
			}
		}
		bool makeParticles = false;
		for (int i = 0; i < jjLocalPlayerCount; i++) {
			const jjPLAYER@ player = jjLocalPlayers[i];
			float camRight = player.cameraX + jjSubscreenWidth;
			float camBottom = player.cameraY + jjSubscreenHeight;
			if (player.cameraX <= obj.xPos + 128.f && camRight >= obj.xPos - 128.f && camBottom >= obj.yPos - 64.f) {
				makeParticles = obj.state == STATE::ROTATE;
				if (player.cameraY <= obj.yPos + 64.f) {
					const auto@ anim = jjAnimations[obj.animSpeed];
					int frame = anim + jjGameTicks % anim.frameCount;
					jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, frame, 0, SPRITE::NORMAL, 0, obj.special, 4, player.playerID);
				}
			}
		}
		if (makeParticles) {
			uint rand = jjRandom();
			if (rand & 3 == 0) {
				rand >>= 2;
				float xSpeed = obj.xSpeed + ((rand & 255) - 127.5f) * 4e-3f;
				rand >>= 8;
				float ySpeed = obj.ySpeed + ((rand & 255) - 127.5f) * 4e-3f;
				rand >>= 8;
				const auto@ anim = jjAnimations[obj.killAnim];
				int frame = anim + rand % anim.frameCount;
				addParticle(obj.xAcc, obj.yAcc, xSpeed, ySpeed, frame);
			}
		}
	}
	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int) {
		if (bullet is null) {
			int invincibility = player.invincibility;
			player.invincibility = 0;
			player.hurt(2);
			player.invincibility = invincibility;
		}
		return true;
	}
}
class Particle {
	bool active;
	float xPos;
	float yPos;
	float xSpeed;
	float ySpeed;
	int frame;
	int age;
	void process() {
		if (active) {
			ySpeed += 0.125f;
			xPos += xSpeed;
			yPos += ySpeed;
			age++;
			if (age == 4) {
				age = 0;
				active = !jjMaskedPixel(int(xPos), int(yPos));
			}
		}
	}
	void draw(jjCANVAS@ canvas) {
		if (active)
			canvas.drawSpriteFromCurFrame(int(xPos), int(yPos), frame, 0, SPRITE::SINGLECOLOR, 0);
	}
}
void addParticle(float xPos, float yPos, float xSpeed, float ySpeed, int frame) {
	auto@ part = particles[jjRandom() & particlesMask];
	part.active = true;
	part.xPos = xPos;
	part.yPos = yPos;
	part.xSpeed = xSpeed;
	part.ySpeed = ySpeed;
	part.frame = frame;
	part.age = 0;
}
array<uint8>@ makeTintedMapping(bool strong) {
	array<uint8> mapping(256);
	for (int i = 0; i < 256; i++) {
		mapping[i] = i;
	}
	for (int i = 96; i < 112; i++) {
		mapping[i] = strong ? (i << 1) - 16 : (i >> 1) + 112;
	}
	for (int i = 112; i < 120; i++) {
		mapping[i] = strong ? (i << 2) - 272 : i + 48;
	}
	for (int i = 128; i < 144; i++) {
		mapping[i] = strong ? (i << 1) - 80 : i + 96;
	}
	for (int i = 143; i < 148; i++) {
		mapping[i] = strong ? 207 : 125;
	}
	for (int i = 148; i < 154; i++) {
		mapping[i] = strong ? (i << 1) - 99 : i - 28;
	}
	for (int i = 170; i < 172; i++) {
		mapping[i] = i - 44;
	}
	for (int i = 172; i < 177; i++) {
		mapping[i] = (i >> 1) + 82;
	}
	return mapping;
}
array<uint8>@ makeSingleColorMapping(uint8 color) {
	array<uint8> result(256, color);
	result[0] = 0;
	return result;
}
void shiftLayer(jjLAYER@ layer, int shift) {
	layer.generateSettableTileArea();
	for (int i = 0; i < layer.height; i++) {
		for (int j = 0; j < layer.widthReal; j++) {
			int tile = layer.tileGet(j, i);
			if (tile != 0)
				layer.tileSet(j, i, tile + shift);
		}
	}
}
const float2@ findNearestBuzzSaw(const float2& pos, float maxDistance) {
	const auto@ layer = jjLayers[4];
	int left = (int(pos.x - maxDistance) + 15) >>> 5;
	if (left < 0)
		left = 0;
	int right = (int(pos.x + maxDistance) + 16) >>> 5;
	if (right > layer.width)
		right = layer.width;
	int top = (int(pos.y - maxDistance) + 15) >>> 5;
	if (top < 0)
		top = 0;
	int bottom = (int(pos.y + maxDistance) + 16) >>> 5;
	if (bottom > layer.height)
		bottom = layer.height;
	const float2@ result;
	for (int i = top; i < bottom; i++) {
		for (int j = left; j < right; j++) {
			if (jjEventGet(j, i) == OBJECT::SPIKEBOLL3D) {
				float2 other(j << 5 | 16, i << 5 | 16);
				float distance = abs(other - pos);
				if (distance < maxDistance) {
					@result = other;
					maxDistance = distance;
				}
			}
		}
	}
	return result;
}
const uint particlesMask = 511;
const float flameX = 119 << 5 | 16;
const float flameY = 99 << 5 | 23;
se::DefaultWeaponHook weaponHook(69);
array<Particle> particles(particlesMask + 1);
array<float2> pickupsToDelete;
jjPAL palette = jjPalette;
bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
	return weaponHook.drawAmmo(player, canvas);
}
void onDrawLayer4(jjPLAYER@, jjCANVAS@ canvas) {
	for (int i = particles.length(); i-- != 0;) {
		particles[i].draw(canvas);
	}
}
void onMain() {
	weaponHook.processMain();
	const auto@ buzzSawFrame = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::CUSTOM[0]]]];
	for (int i = 1; i < jjObjectCount; i++) {
		jjOBJ@ obj = jjObjects[i];
		if (obj.isActive) {
			if (obj.playerHandling == HANDLING::PICKUP) {
				float2 org(obj.xOrg, obj.yOrg);
				float2 pos(obj.xPos, obj.yPos);
				const float2@ buzzSaw = findNearestBuzzSaw(pos, 80.f);
				if (buzzSaw !is null && jjAnimFrames[obj.curFrame].doesCollide(int(pos.x), int(pos.y), obj.direction, buzzSawFrame, int(buzzSaw.x), int(buzzSaw.y), 0, true)) {
					obj.particlePixelExplosion(0);
					if (obj.counterEnd++ >= 16) {
						if (obj.creatorType != CREATOR::OBJECT || jjObjects[obj.creatorID].eventID == OBJECT::GENERATOR) {
							jjSTREAM packet;
							packet.push(uint8(0));
							packet.push(float(obj.xOrg));
							packet.push(float(obj.yOrg));
							jjSendPacket(packet);
						}
						obj.delete();
					} else if (pickupsToDelete.find(org) >= 0) {
						obj.delete();
					}
				} else if (pickupsToDelete.find(org) >= 0) {
					obj.behavior = BEHAVIOR::EXPLOSION2;
				}
			} else if (obj.eventID == OBJECT::LASERSHIELD) {
				jjDrawSprite(flameX, flameY, ANIM::PLUS_SCENERY, 1, jjGameTicks / 7, 0, SPRITE::PALSHIFT, 32);
			}
		}
	}
	pickupsToDelete.resize(0);
	for (int i = particles.length(); i-- != 0;) {
		particles[i].process();
	}
}
void onPlayer(jjPLAYER@ player) {
	if (player.shieldTime > 0 && player.blink == -210)
		player.shieldTime -= 700;
	weaponHook.processPlayer(player);
}
void onPlayerInput(jjPLAYER@ player) {
	weaponHook.processPlayerInput(player);
}
void onReceive(jjSTREAM &in packet, int clientID) {
	if (!weaponHook.processPacket(packet, clientID)) {
		jjSTREAM copy = packet;
		float2 pos;
		if (packet.discard(1) && packet.pop(pos.x) && packet.pop(pos.y)) {
			pickupsToDelete.insertLast(pos);
			if (jjIsServer)
				jjSendPacket(copy, -clientID);
		}
	}
}
void onLevelLoad() {
	jjDelayGeneratedCrateOrigins = true;
	jjUseLayer8Speeds = true;
	jjTexturedBGTexture = TEXTURE::WINDSTORMFORTRESS;
	const uint tileCount = jjTileCount;
	if (jjTilesFromTileset(jjTilesetFileName, 0, tileCount, makeTintedMapping(false)))
		shiftLayer(jjLayers[6], tileCount);
	if (jjTilesFromTileset(jjTilesetFileName, 0, tileCount, makeTintedMapping(true)))
		shiftLayer(jjLayers[7], tileCount * 2);
	if (jjTilesFromTileset("Buildsit.j2t", 20, 60, makeSingleColorMapping(207))) {
		shiftLayer(jjLayers[1], tileCount * 3);
		shiftLayer(jjLayers[2], tileCount * 3 + 39);
	}
	for (uint i = tileCount * 3 + 60; i-- != tileCount * 2;) {
		jjTileType[i] = 1;
	}
	auto@ order = jjLayerOrderGet();
	for (int i = 0; i < 2; i++) {
		order.insertAt(6, order[0]);
		order.removeAt(0);
	}
	jjLayerOrderSet(order);
	jjAnimSets[ANIM::PLUS_SCENERY].load();
	jjAnimSets[ANIM::CUSTOM[0]].load(0, "cleanSE.j2a");
	if (palette.load("cleanSE.pal"))
		palette.apply();
	auto@ saw = jjObjectPresets[OBJECT::SPIKEBOLL3D];
	saw.behavior = BuzzSaw();
	saw.bulletHandling = HANDLING::IGNOREBULLET;
	saw.scriptedCollisions = true;
	saw.curAnim = jjAnimSets[ANIM::CUSTOM[0]];
	saw.animSpeed = saw.curAnim + 1;
	saw.killAnim = saw.curAnim + 2;
	saw.determineCurFrame();
	se::energyBlast.loadAnims(jjAnimSets[ANIM::CUSTOM[1]]);
	se::energyBlast.loadSamples(array<SOUND::Sample> = {SOUND::INTRO_BLOW});
	se::energyBlast.setAsWeapon(3, weaponHook);
}
void onLevelReload() {
	palette.apply();
}