Downloads containing SEast.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Anniversary Bash 22 levels Jazz2Online Multiple N/A Download file
TSF with JJ2+ Only: AstolfoFeatured Download Seren Battle 10 Download file

File preview

#pragma require "SEroller.asc"
#include "SEroller.asc"
funcdef float EasingFunction(float);
class Point {
	int x, y;
	Point() {}
	Point(int X, int Y) {
		x = X;
		y = Y;
	}
}
class Timer {
	private EasingFunction@ easing;
	private const jjANIMATION@ anim;
	private int animFrameDelay;
	private int frameCounter;
	private int curFrame;
	private bool visible;
	private int visibility;
	private int maxVisibility;
	private float posAlpha;
	private float posBeta;
	private int time;
	private string oldText;
	private string newText;
	private STRING::Size size;
	private int transition;
	private int maxTransition;
	private int textAlpha;
	private int textBeta;
	private float offsetAlpha;
	private float offsetBeta;
	private float maxOffset;
	jjTEXTAPPEARANCE style;
	Timer() {
		@easing = function(t) {
			const float c = 1.70158f;
			const float a3 = c + 1.f;
			const float a2 = -2.f * c - 3.f;
			const float a1 = c + 3.f;
			return t * (t * (t * a3 + a2) + a1);
		};
		@anim = jjAnimations[jjAnimSets[ANIM::PICKUPS] + 40];
		animFrameDelay = 4;
		maxVisibility = 35;
		size = STRING::MEDIUM;
		maxTransition = 15;
		maxOffset = 16.f;
	}
	void setVisible(bool value) {
		visible = value;
	}
	void setTime(int value, bool playSample) {
		if (time != value) {
			time = value;
			oldText = newText;
			newText = formatInt(value);
			transition = visibility == 0 ? maxTransition : 0;
			if (playSample)
				jjSamplePriority(value == 0 ? SOUND::COMMON_BELL_FIRE : SOUND::COMMON_BELL_FIRE2);
		}
	}
	void process() {
		frameCounter++;
		curFrame = anim + frameCounter / animFrameDelay % anim.frameCount;
		if (visible) {
			if (visibility < maxVisibility)
				visibility++;
		} else {
			if (visibility > 0)
				visibility--;
		}
		float t = float(visibility) / maxVisibility;
		posBeta = easing(t);
		posAlpha = 1.f - posBeta;
		if (transition < maxTransition) {
			transition++;
			float a = float(transition) / maxTransition;
			textBeta = int(a * 255.f);
			textAlpha = 255 - textBeta;
			offsetAlpha = -a * maxOffset;
			offsetBeta = maxOffset + offsetAlpha;
		}
	}
	void draw(jjCANVAS@ canvas, float x0, float y0, float x1, float y1) const {
		int x = int(x0 * posAlpha + x1 * posBeta);
		float y = y0 * posAlpha + y1 * posBeta;
		if (curFrame != 0)
			canvas.drawSpriteFromCurFrame(x, int(y), curFrame);
		x += jjAnimFrames[anim].width + jjAnimFrames[anim].hotSpotX;
		canvas.drawString(x, int(y + offsetAlpha), oldText, size, style, 0, SPRITE::BLEND_NORMAL, textAlpha);
		canvas.drawString(x, int(y + offsetBeta), newText, size, style, 0, SPRITE::BLEND_NORMAL, textBeta);
	}
}
const array<int> powerupEventIDs = {
	OBJECT::BLASTERPOWERUP,
	OBJECT::BOUNCERPOWERUP,
	OBJECT::ICEPOWERUP,
	OBJECT::SEEKERPOWERUP,
	OBJECT::RFPOWERUP,
	OBJECT::TOASTERPOWERUP,
	OBJECT::TNTPOWERUP,
	OBJECT::GUN8POWERUP,
	OBJECT::GUN9POWERUP,
};
bool powerupsEnabled = false;
int powerupSpawnTimesAtPrevTick = -3;
se::DefaultWeaponHook weaponHook;
array<Point> oneWays;
array<bool> specialMove(jjLocalPlayerCount);
array<int> fastSpringSpeeds(jjLocalPlayerCount);
array<int> flyCarrotTime(jjLocalPlayerCount);
array<Timer> flyCarrotTimers(jjLocalPlayerCount);
void prepareOneWays() {
	for (int i = 0; i < jjLayerHeight[4]; i++) {
		for (int j = 0; j < jjLayerWidth[4]; j++) {
			if (jjEventGet(j, i) == AREA::ONEWAY)
				oneWays.insertLast(Point(j, i));
		}
	}
}
void enforceOneWays(jjPLAYER@ player) {
	bool previousSpecialMove = specialMove[player.localPlayerID];
	bool currentSpecialMove = player.specialMove != 0 && jjCharacters[player.charCurr].groundJump != GROUND::JAZZ;
	if (currentSpecialMove ^^ previousSpecialMove) {
		for (uint i = 0; i < oneWays.length(); i++) {
			const Point@ tile = oneWays[i];
			jjEventSet(tile.x, tile.y, currentSpecialMove ? 0 : AREA::ONEWAY);
		}
		specialMove[player.localPlayerID] = currentSpecialMove;
	}
}
void handleFastSpringSpeeds(jjPLAYER@ player) {
	if (player.ySpeed < -32.f) {
		fastSpringSpeeds[player.localPlayerID] = int(ceil((player.ySpeed + 32.f) / -0.125f));
	} else if (fastSpringSpeeds[player.localPlayerID] != 0) {
		if (player.ySpeed < -31.f) {
			fastSpringSpeeds[player.localPlayerID]--;
			player.ySpeed = -32.f;
		} else {
			fastSpringSpeeds[player.localPlayerID] = 0;
		}
	}
}
void handleFlight(jjPLAYER@ player) {
	Timer@ timer = flyCarrotTimers[player.localPlayerID];
	if (flyCarrotTime[player.localPlayerID] > 0) {
		if (player.fly == FLIGHT::FLYCARROT) {
			flyCarrotTime[player.localPlayerID]--;
			if (flyCarrotTime[player.localPlayerID] == 0)
				player.fly = FLIGHT::NONE;
			timer.setTime((flyCarrotTime[player.localPlayerID] + 69) / 70, flyCarrotTime[player.localPlayerID] < 250);
		} else {
			flyCarrotTime[player.localPlayerID] = 0;
		}
	}
	timer.setVisible(flyCarrotTime[player.localPlayerID] > 0);
	timer.process();
}
void moveGenerators() {
	array<Point> positions;
	for (int i = 1; i < jjObjectCount; i++) {
		jjOBJ@ obj = jjObjects[i];
		if (obj.isActive) {
			Point position(int(obj.xPos) >>> 5, int(obj.yPos) >>> 5);
			int tile = jjTileGet(2, position.x, position.y);
			if (tile != 0) {
				obj.xPos += ((tile + 2) % 9 - 1 << 5) / 3.f;
				obj.yPos += ((tile + 2) / 9 - 3 << 5) / 3.f;
				positions.insertLast(position);
			}
		}
	}
	for (int i = positions.length(); i-- != 0;) {
		const Point@ position = positions[i];
		jjTileSet(2, position.x, position.y, 0);
	}
	jjLayerHasTiles[2] = false;
}
void detectPowerupsEnabled() {
	if (jjIsServer) {
		int powerupSpawnTimes = -1;
		for (int i = 1; i < jjObjectCount; i++) {
			const jjOBJ@ obj = jjObjects[i];
			if (obj.eventID == OBJECT::GENERATOR && powerupEventIDs.find(obj.var[3]) >= 0) {
				if (obj.var[0] > 0 && jjObjects[obj.var[0]].isActive && jjObjects[obj.var[0]].creatorID == uint(i)) {
					powerupSpawnTimes = -2;
					break;
				} else if (powerupSpawnTimes == -1) {
					powerupSpawnTimes = obj.var[1];
				} else if (obj.var[1] != powerupSpawnTimes) {
					powerupSpawnTimes = -2;
					break;
				}
			}
		}
		bool newPowerupsEnabled = powerupSpawnTimesAtPrevTick == -3 ? powerupsEnabled : powerupSpawnTimes == -2 || powerupSpawnTimes != powerupSpawnTimesAtPrevTick;
		powerupSpawnTimesAtPrevTick = powerupSpawnTimes;
		if (newPowerupsEnabled != powerupsEnabled) {
			powerupsEnabled = newPowerupsEnabled;
			jjSTREAM packet;
			packet.push(powerupsEnabled);
			jjSendPacket(packet);
		}
	}
}
void grantPoints(jjPLAYER@ player, jjOBJ@ obj) {
	if (obj.points > 0 && (jjGameMode == GAME::SP || jjGameMode == GAME::COOP)) {
		player.score += obj.points;
		jjPARTICLE@ part = jjAddParticle(PARTICLE::STRING);
		if (part !is null) {
			part.xPos = obj.xPos;
			part.yPos = obj.yPos;
			part.xSpeed = -(0x8000 + (jjRandom() & 0x3FFF)) / float(0x10000);
			part.ySpeed = -(0x10000 + (jjRandom() & 0x7FFF)) / float(0x10000);
			part.string.text = formatInt(obj.points);
		}
		obj.points = 0;
	}
}
float getPickupY(const jjOBJ@ obj) {
	bool floating = obj.state == STATE::FLOAT || obj.behavior != BEHAVIOR::PICKUP;
	int arg = (((obj.objectID << 3) + jjGameTicks) << (floating && obj.yPos > jjWaterLevel ? 1 : 4)) + (floating ? int(obj.xPos) << 4 : 0);
	return obj.yPos + jjSin(arg) * 4.f;
}
void turnPickupIntoFlyCarrot(jjOBJ@ obj, int time) {
	const jjOBJ@ flyCarrot = jjObjectPresets[OBJECT::FLYCARROT];
	obj.eventID = OBJECT::FLYCARROT;
	obj.counter = time;
	obj.curAnim = flyCarrot.curAnim;
	obj.curFrame = flyCarrot.curFrame;
	obj.points = flyCarrot.points;
	obj.scriptedCollisions = true;
}
void drawFlyCarrotPickupTimer(const jjOBJ@ obj, int alpha = 255, int layer = 4) {
	jjTEXTAPPEARANCE style;
	style.align = STRING::CENTER;
	jjDrawString(obj.xPos - 3.f, obj.yPos + 22.f, formatInt(obj.counter / 70), STRING::SMALL, style, 0, SPRITE::BLEND_LUMINANCE, alpha, layer);
}
bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
	flyCarrotTimers[player.localPlayerID].draw(canvas, jjSubscreenWidth + 32, jjSubscreenHeight / 2, jjSubscreenWidth - 64, jjSubscreenHeight / 2);
	return weaponHook.drawAmmo(player, canvas);
}
void onLevelBegin() {
	jjWeapons[WEAPON::GUN8].allowedPowerup = true;
	moveGenerators();
}
void onLevelLoad() {
	if (!jjIsServer)
		jjSendPacket(jjSTREAM());
	jjUseLayer8Speeds = true;
	prepareOneWays();
	jjObjectPresets[OBJECT::BLUESPRING].ySpeed = -35.f;
	turnPickupIntoFlyCarrot(jjObjectPresets[OBJECT::EXTRATIME], 490);
	turnPickupIntoFlyCarrot(jjObjectPresets[OBJECT::EXTRALIFE], 700);
	se::roller.loadAnims(jjAnimSets[ANIM::CUSTOM[0]]);
	se::roller.loadSamples(array<SOUND::Sample> = {SOUND::INTRO_BLOW});
	se::roller.setAsWeapon(4, weaponHook);
}
void onMain() {
	for (int i = 6; i <= 7; i++) {
		jjLayerXOffset[i] = (jjLayerXOffset[i] + (i == 6 ? -1.f : 1.f)) % (jjLayerWidth[i] * 32);
	}
	for (int i = 1; i < jjObjectCount; i++) {
		const jjOBJ@ obj = jjObjects[i];
		if (obj.playerHandling == HANDLING::PICKUP) {
			int x = int(obj.xPos);
			int y = int(obj.yPos);
			int tile = jjTileGet(3, x >>> 5, y >>> 5);
			bool isFlyCarrot = obj.eventID == OBJECT::FLYCARROT;
			if (isFlyCarrot)
				drawFlyCarrotPickupTimer(obj);
			if (tile != 0) {
				jjPIXELMAP image(tile);
				if (image[x & 31, y & 31] != 0) {
					int alpha = jjAnimFrames[obj.curFrame].transparent ? 32 : 64;
					jjDrawSpriteFromCurFrame(obj.xPos, getPickupY(obj), obj.curFrame, obj.direction, SPRITE::BLEND_NORMAL, alpha, 3);
					if (isFlyCarrot)
						drawFlyCarrotPickupTimer(obj, alpha, 3);
				}
			}
		}
	}
	detectPowerupsEnabled();
	weaponHook.processMain();
}
void onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int) {
	if (bullet is null && obj.eventID == OBJECT::FLYCARROT) {
		player.fly = FLIGHT::FLYCARROT;
		player.doubleJumpCount = 0;
		if (player.isLocal && flyCarrotTime[player.localPlayerID] < obj.counter)
			flyCarrotTime[player.localPlayerID] = obj.counter;
		grantPoints(player, obj);
		obj.frameID = 0;
		obj.behavior = BEHAVIOR::EXPLOSION2;
		jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PICKUP1);
	}
}
void onPlayer(jjPLAYER@ player) {
	if (jjColorDepth == 8) {
		jjEnforceLighting = LIGHT::COMPLETE;
		player.lighting = 110;
	} else {
		jjEnforceLighting = LIGHT::OPTIONAL;
		player.lighting = 100;
	}
	if (player.ammo[WEAPON::GUN8] == 0 || !player.powerup[WEAPON::GUN8])
		player.powerup[WEAPON::GUN8] = powerupsEnabled;
	enforceOneWays(player);
	handleFastSpringSpeeds(player);
	handleFlight(player);
	weaponHook.processPlayer(player);
}
void onPlayerInput(jjPLAYER@ player) {
	weaponHook.processPlayerInput(player);
}
void onReceive(jjSTREAM &in packet, int clientID) {
	if (jjIsServer) {
		jjSTREAM response;
		response.push(powerupsEnabled);
		jjSendPacket(response, clientID);
	} else {
		packet.pop(powerupsEnabled);
	}
}