Downloads containing ab19ctf19.j2as

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

File preview

#pragma require "FTURROCK.wav"
#pragma require "EXPSTD3.wav"
#pragma require "redeemer_flight.wav"
#pragma require "wind1.wav"
#pragma require "SHIPHUMS.wav"
#pragma require "ab19ctf19ex.j2l"
#pragma require "ab19ctf19ex2.j2l"

bool gameIsActive() {
	return jjGameState == GAME::STARTED || jjGameState == GAME::OVERTIME;
}

bool CTFMode() {
	return (jjGameMode == GAME::CTF && jjGameCustom == GAME::NOCUSTOM) || jjGameCustom == GAME::DCTF;
}

bool otherMode() {
	return jjGameMode != GAME::CTF || jjGameCustom == GAME::TB || jjGameCustom == GAME::TLRS || jjGameCustom == GAME::DOM;
}

bool muteAmbientWind() {
	return (jjLocalPlayers[0].xPos < 22*32 && jjLocalPlayers[0].yPos < 46*32) || (jjLocalPlayers[0].xPos > 258*32 && jjLocalPlayers[0].yPos < 46*32);
}

bool isWindSound(jjOBJ@ sound) {
	return sound.xOrg >= 277*32;
}

bool isShipSound(jjOBJ@ sound) {
	return sound.xOrg <= 2*32;
}

const array<uint16> invisibleTiles = {
	75,
	102, 103,
	112, 113, 116, 117, 118, 119,
	122, 123, 126, 127, 128, 129,
	132, 133,
	142, 143,
	152, 153
};

bool controllingRedeemer, warning = false;
int xPos = 0, yPos = 0;
int CTFArrowTimer = 0;
uint delay = 0;

int redeemerColor(jjPLAYER@ creator) {
	switch(creator.team) {
		case TEAM::BLUE: return 0;
		case TEAM::RED: return 1;
		case TEAM::GREEN: return 2;
		case TEAM::YELLOW: return 3;
	}
	return 0;
}

uint8 getTeamColor(TEAM::Color team) {
	switch (team) {
		case TEAM::BLUE: return 32;
		case TEAM::RED: return 24;
	}
	return 32;
}

const array<TEAM::Color> teams = {TEAM::BLUE, TEAM::RED, TEAM::GREEN, TEAM::YELLOW};
const float PI = 3.1415927f;

void onLevelLoad() {
	jjSampleLoad(SOUND::P2_POEP, "FTURROCK.wav");
	jjSampleLoad(SOUND::P2_PTOEI, "EXPSTD3.wav");
	jjSampleLoad(SOUND::P2_SPLOUT, "redeemer_flight.wav");
	jjSampleLoad(SOUND::SCIENCE_PLOPKAOS, "wind1.wav");
	jjSampleLoad(SOUND::COMMON_COLLAPS, "SHIPHUMS.wav");

	jjAnimSets[ANIM::SONCSHIP].load();
	jjAnimSets[ANIM::VINE].load();
	jjAnimations[jjAnimSets[ANIM::AMMO] + 59] = jjAnimations[jjAnimSets[ANIM::SONCSHIP] + 0];
	
	jjTexturedBGFadePositionY = 0.1;
	jjUseLayer8Speeds = true;
	
	jjObjectPresets[OBJECT::AIRBOARD].behavior = CantTakeWhenFlying();
	
	jjObjectPresets[OBJECT::LIGHTNINGSHIELD].behavior = 
	jjObjectPresets[OBJECT::RFPOWERUP].behavior = OscillatingMonitor();
	
	jjObjectPresets[OBJECT::AMBIENTSOUND].behavior = AmbientSound();
	
	jjObjectPresets[OBJECT::TNT].determineCurFrame();
	jjObjectPresets[OBJECT::TNT].behavior = Redeemer();
	jjObjectPresets[OBJECT::TNT].xSpeed = jjObjectPresets[OBJECT::BLASTERBULLET].xSpeed * 1.33;
	jjObjectPresets[OBJECT::TNT].counterEnd = 255;
	jjObjectPresets[OBJECT::TNT].killAnim = jjObjectPresets[OBJECT::SEEKERBULLET].killAnim;
	
	jjObjectPresets[OBJECT::TNTAMMO3].behavior = RedeemerPickup();
	jjObjectPresets[OBJECT::TNTAMMO3].determineCurFrame();
	jjObjectPresets[OBJECT::TNTAMMO3].scriptedCollisions = true;
	
	jjWeapons[WEAPON::TNT].maximum = 1;
	jjWeapons[WEAPON::GUN8].comesFromGunCrates = true;
	
	jjLayerXOffset[6] = 128;
	
	array<jjLAYER@> extraLayers = jjLayersFromLevel("ab19ctf19ex.j2l", array<uint> = {1,2,3,5,6,7}, 0);
	array<jjLAYER@> extraLayers2 = jjLayersFromLevel("ab19ctf19ex2.j2l", array<uint> = {5,6,7}, 0);
	jjLayerOrderSet(array<jjLAYER@> = {extraLayers[0], extraLayers[1], extraLayers2[0], extraLayers2[1], extraLayers2[2], jjLayers[3], jjLayers[1], jjLayers[4], jjLayers[2], jjLayers[5], extraLayers[2], jjLayers[6], jjLayers[7], extraLayers[3], extraLayers[4], extraLayers[5], jjLayers[8]});
	
	extraLayers[1].spriteMode = SPRITE::TRANSLUCENTCOLOR;
	extraLayers[1].spriteParam = 86;
	
	extraLayers[2].xOffset = 100;
	extraLayers[2].yOffset = 360;
	extraLayers[3].xOffset = 80;
	extraLayers[3].yOffset = 120;
	extraLayers[4].xOffset = 160;
	extraLayers[4].yOffset = 140;
	extraLayers[5].xOffset = 320;
	extraLayers[5].yOffset = 160;
	
	extraLayers2[0].xOffset = 200;
	extraLayers2[0].yOffset = -1700;
	extraLayers2[1].xOffset = 300;
	extraLayers2[1].yOffset = -1600;
	extraLayers2[2].xOffset = 400;
	extraLayers2[2].yOffset = -1500;
	
	for (uint16 i = 0; i < invisibleTiles.length(); i++) {
		jjTileType[invisibleTiles[i]] = 3; //invisible
	}
	jjTileType[1176] = 5;
	
	generateColoredRedeemerSprites(jjAnimSets[ANIM::CUSTOM[0]], array<uint> = {32, 24, 16, 40});
}

jjANIMSET@ coloredRedeemerSprite;
bool generateColoredRedeemerSprites(jjANIMSET@ anim, const array<uint> &in colors) {
	int length = colors.length();
	bool success = (@coloredRedeemerSprite = anim).allocate(array<uint>(length * 3, 8)) !is null;
	if (success) {
		uint srcSet = jjAnimSets[ANIM::SONCSHIP];
		for (int i = 0; i < length; i++) {
			uint color = colors[i];
			uint destAnimOffset = anim + i;
			for (int j = 0; j < 4; j++) {
				uint srcAnim = jjAnimations[srcSet + 0];
				uint destAnim = jjAnimations[destAnimOffset + j];
				for (int k = 0; k < 8; k++) {
					jjPIXELMAP image(jjAnimFrames[destAnim + k] = jjAnimFrames[srcAnim + k]);
					int width = image.width;
					int height = image.height;
					for (int l = 0; l < height; l++) {
						for (int m = 0; m < width; m++) {
							int pixel = image[m, l];
							if (pixel >= 88 && pixel < 96)
								image[m, l] = color + (pixel & 7);
						}
					}
					if (!image.save(jjAnimFrames[destAnim + k]))
						return false;
				}
			}
		}
	}
	return success;
}

class CantTakeWhenFlying : jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ obj) {
		obj.behave(BEHAVIOR::PICKUP);
		if (jjLocalPlayers[0].fly == FLIGHT::AIRBOARD) obj.playerHandling = HANDLING::PARTICLE;
		else obj.playerHandling = HANDLING::PICKUP;
		if (obj.state == STATE::FLOATFALL) obj.state = STATE::FLOAT;
	}
}

class OscillatingMonitor : jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ obj) {
		obj.behave(BEHAVIOR::MONITOR);
		obj.xPos = obj.xOrg - 4;
		obj.yPos = (obj.yOrg + 2) - jjLayerYOffset[2];
		obj.direction = -1;
	}
}

class AmbientSound : jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ sound) {
		sound.behave(jjLowDetail? BEHAVIOR::INACTIVE : BEHAVIOR::AMBIENTSOUND, false);
		if (jjLocalPlayers[0].health > 0) delay++;
		else delay = 0;
		
		if (jjTriggers[19] && isWindSound(sound) && delay >= 35) {
			loopSound(sound);
		}
		if (!jjTriggers[19] && isShipSound(sound) && delay >= 35) {
			loopSound(sound);
		}
	
		if ((muteAmbientWind() && isWindSound(sound)) || jjLocalPlayers[0].health == 0) {
			jjTriggers[19] = false;
			sound.xPos = sound.xOrg;
			sound.yPos = sound.yOrg;
		}
	}
}

void loopSound(jjOBJ@ sound) {
	sound.xPos = jjLocalPlayers[0].xPos;
	sound.yPos = jjLocalPlayers[0].yPos;
}

class Redeemer : jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ obj) {
		//var[0] - angle
		//var[1] - angular speed
		//var[2] - was explosion sample already played
		//special - value of jjGameTicks at the time the last packet was sent/received
		int angle;
		float speed = jjObjectPresets[OBJECT::TNT].xSpeed;
		
		if (obj.creatorType != CREATOR::PLAYER)
			obj.delete();
		jjPLAYER@ creator = jjPlayers[obj.creatorID];
		
		switch (obj.state) {
			case STATE::START:
				obj.curAnim = jjObjectPresets[obj.eventID].curAnim;
				jjSamplePriority(SOUND::P2_POEP);
				obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
				obj.ySpeed = speed * -jjSin(obj.var[0]);
				obj.xSpeed = speed * jjCos(obj.var[0]);
				obj.direction = obj.xSpeed < 0.f ? -1 : 1;
				obj.state = STATE::FLY;
			break;
				
			case STATE::FLY:
				redeemerCamera(creator, obj);
				jjDrawRotatedSprite(obj.xPos, obj.yPos, (creator.isLocal || jjGameMode != GAME::CTF)? ANIM::SONCSHIP : ANIM::CUSTOM[0], (creator.isLocal || jjGameMode != GAME::CTF)? 0 : redeemerColor(creator), obj.curFrame, obj.var[0], 2, 2, SPRITE::NORMAL);
				if (creator.isLocal) {
					controllingRedeemer = true;
					if (!jjLowDetail && (obj.counter % 131 == 36 || obj.counter == 1)) jjSamplePriority(SOUND::P2_SPLOUT);
					float dx = creator.xPos - obj.xPos, dy = creator.yPos - obj.yPos;
						if (dx * dx + dy * dy < 352 * 352) warning = true;
						else warning = false;
					if (creator.health == 0) {
						creator.cameraUnfreeze(true);
						obj.state = STATE::EXPLODE;
					} else {
						creator.xSpeed = 0;
						if (obj.counter >= 21) {
							if (creator.keyRight || (obj.direction < 0 ? creator.keyUp : creator.keyDown))
								obj.var[1] = -16;
							else if (creator.keyLeft || (obj.direction < 0 ? creator.keyDown : creator.keyUp))
								obj.var[1] = 16;
							else
								obj.var[1] = 0;
						}
						if (obj.counter == 127)
							obj.counter = 35;
						else if (obj.counter >= 35 && creator.keyFire)
							obj.state = STATE::EXPLODE;
					}
					xPos = int(obj.xPos);
					yPos = int(obj.yPos);
				}
				if (obj.yPos >= jjLayerHeight[4]*32) obj.state = STATE::EXPLODE;
				obj.var[0] = obj.var[0] + obj.var[1];
				obj.ySpeed = speed * -jjSin(obj.var[0]);
				obj.xSpeed = speed * jjCos(obj.var[0]);
				if (obj.counter % 3 == 0 && !jjLowDetail) spawnFireTrail(obj);
			break;
			
			case STATE::EXPLODE:
				jjDrawResizedSprite(obj.xPos, obj.yPos, ANIM::AMMO, 5, obj.curFrame + 5, 12, 12, SPRITE::NORMAL, 0, 1);
				creator.cameraUnfreeze(true);
				if (creator.isLocal) controllingRedeemer = false;
				if (obj.var[2] == 0) {
					jjSamplePriority(SOUND::P2_PTOEI);
					obj.var[2] = 1;
				}
				if (jjIsServer && jjGameTicks % 21 == 0 && gameIsActive()) {
					for (int i = 0; i < 32; i++) {
						jjPLAYER@ player = jjPlayers[i];
						if (
							player.isActive && player.isInGame && player.health > 0 &&
							(jjGameMode != GAME::CTF || jjFriendlyFire || player.team != creator.team || player is creator)
						) {
							float dx = player.xPos - obj.xPos, dy = player.yPos - obj.yPos;
							if (dx * dx + dy * dy < 352 * 352)
								player.hurt(2, true, creator);
						}
					}
				}
			break;
		}
		
		int previousState = obj.state;
		obj.behave(BEHAVIOR::BULLET, false);
		if (!creator.isLocal) {
			if (obj.special + 128 > jjGameTicks)
				obj.state = previousState;
		} else if (obj.special + 4 <= jjGameTicks) {
			jjSTREAM packet;
			packet.push(int8(obj.creatorID));
			packet.push(obj.state == STATE::EXPLODE);
			packet.push(obj.xPos);
			packet.push(obj.yPos);
			if (obj.state != STATE::EXPLODE) {
				packet.push(int16(obj.var[0]));
				packet.push(int16(obj.var[1]));
			}
			jjSendPacket(packet);
			obj.special = jjGameTicks;
		}
	}
}

void spawnFireTrail(jjOBJ@ obj) {
	jjOBJ@ trail = jjObjects[jjAddObject(OBJECT::EXPLOSION, int(obj.xPos - jjCos(obj.var[0])), int(obj.yPos - jjSin(obj.var[0])))];
	trail.determineCurAnim(ANIM::AMMO, 3);
	trail.lightType = LIGHT::POINT;
}

void redeemerCamera(jjPLAYER@ creator, jjOBJ@ obj) {
	float dx = jjLayerWidth[4] - obj.xPos, dy = jjLayerHeight[4] - obj.yPos;
	int cameraX, cameraY;
	
	if (jjLayerWidth[4] - dx <= 400) cameraX = 400;
	else cameraX = int(obj.xPos);
	
	if (jjLayerHeight[4] - dy <= 400) cameraY = 400;
	else cameraY = int(obj.yPos);
	
	creator.cameraFreeze(int(obj.xPos) >= 8528? 8528 : cameraX, int(obj.yPos) >= 4080? 4080 : cameraY, true, true);
	
	for (int i = 0; i < 32; i++) {
		jjPLAYER@ play = jjPlayers[i];
		float pdx = play.xPos - obj.xPos, pdy = play.yPos - obj.yPos;
		if ((pdx * pdx + pdy * pdy < 300 * 300) && (jjGameMode != GAME::CTF || jjFriendlyFire || play.team != creator.team) && !play.isLocal)
			jjDrawResizedSprite(play.xPos, play.yPos, ANIM::SONCSHIP, 7, 0, 2, 2, SPRITE::SINGLECOLOR, 72, 1);
	}
}

class RedeemerPickup : jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ obj) {
		obj.behave(BEHAVIOR::PICKUP, false);
		obj.direction = obj.xPos > 4464? -1:-1;
		if (obj.isActive) jjDrawResizedSpriteFromCurFrame(obj.xPos, int(obj.yPos) + jjSin(jjGameTicks*10)*6, obj.curFrame, 2 * obj.direction, 2, ((obj.xPos < 4464 && jjLocalPlayers[0].team == TEAM::BLUE) || (obj.xPos > 4464 && jjLocalPlayers[0].team == TEAM::RED))? SPRITE::NORMAL : SPRITE::TRANSLUCENTSINGLEHUE, jjLocalPlayers[0].team == TEAM::BLUE? 24:32);
	}
	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) {
		if (play.ammo[WEAPON::TNT] < jjWeapons[WEAPON::TNT].maximum) {
			if ((obj.xPos < 4464 && play.team == TEAM::BLUE) || (obj.xPos > 4464 && play.team == TEAM::RED) || otherMode()) {
				if (play.isLocal) {
					play.ammo[WEAPON::TNT] = play.ammo[WEAPON::TNT] + 1;
					if (jjAutoWeaponChange) play.currWeapon = WEAPON::TNT;
					jjSample(obj.xPos, obj.yPos, SOUND::COMMON_LOADSPAZ, 0, 0);
				}
				obj.behavior = BEHAVIOR::EXPLOSION2;
				obj.scriptedCollisions = false;
				obj.frameID = 0;
			}
		}
		return true;
	}
}

void onReceive(jjSTREAM &in packet, int clientID) {
	int8 playerID;
	bool explosion;
	float xPos, yPos;
	int16 angle, angleSpeed;
	jjSTREAM packetBackup;
	if (jjIsServer)
		packetBackup = packet;
	if (packet.pop(playerID) && playerID >= 0 && playerID < 32 &&
		packet.pop(explosion) && packet.pop(xPos) && packet.pop(yPos) &&
		(explosion || packet.pop(angle) && packet.pop(angleSpeed))
	) {
		const jjPLAYER@ player = jjPlayers[playerID];
		if (!jjIsServer || player.isActive && player.isInGame && player.clientID == clientID ) {
			for (int i = 0; i < jjObjectCount; i++) {
				jjOBJ@ obj = jjObjects[i];
				if (obj.isActive && obj.eventID == OBJECT::TNT && obj.creatorType == CREATOR::PLAYER && obj.creatorID == uint(playerID)) {
					if (jjIsServer)
						jjSendPacket(packetBackup, -clientID);
					if (explosion)
						obj.state = STATE::EXPLODE;
					obj.xPos = xPos;
					obj.yPos = yPos;
					obj.var[0] = angle;
					obj.var[1] = angleSpeed;
					obj.special = jjGameTicks;
					break;
				}
			}
		}
	}
}

void onPlayer(jjPLAYER@ play) {
	if (play.shieldTime > 20*70) play.shieldTime = 20*70;
	
	if (play.fly == FLIGHT::AIRBOARD && play.timerState == TIMER::STOPPED) play.timerStart(20*70);
	if (play.fly == FLIGHT::NONE) play.timerStop();
  	if (play.timerState == TIMER::STARTED && play.timerTime <= 3*70 && play.timerTime > 0 && play.timerTime % 70 == 0) jjSamplePriority(SOUND::COMMON_NOCOIN);
}

void onPlayerTimerEnd(jjPLAYER@ play) { play.fly = FLIGHT::NONE; }

void onMain() {
	if (!jjLowDetail) {
		jjLayerYOffset[1] = jjCos(jjGameTicks*8)*4;
		jjLayerYOffset[2] = jjCos(jjGameTicks*8)*4;
	} else {
		jjLayerYOffset[1] = 
		jjLayerYOffset[2] = 0;
	}
	
	array<jjLAYER@> layers = jjLayerOrderGet();
	layers[0].hasTiles = layers[1].hasTiles = controllingRedeemer;
	
	if (controllingRedeemer && CTFMode()) {
		if (CTFArrowTimer > jjGameTicks + 280) CTFArrowTimer = jjGameTicks;
		if (CTFArrowTimer < jjGameTicks) {
			if (CTFArrowTimer + 64 >= jjGameTicks) {
				for (int i = 0; i < 32; i++) {
					jjPLAYER@ target = jjPlayers[i];
					if (target.flag != 0 && target.team != jjLocalPlayers[0].team) {
						int angle = int(atan2(target.yPos - yPos, target.xPos - xPos) * (512 / PI));
						const float scale = 64.f / (112.f - jjSin((jjGameTicks - CTFArrowTimer) << 3) * 64.f);
						jjDrawRotatedSprite(xPos + 32 * jjCos(angle), yPos + 32 * jjSin(angle), ANIM::FLAG, 0, 0, 970 - angle, scale, scale, SPRITE::PALSHIFT, getTeamColor(target.team) - 32, 1);
					}
				}
			} else {
				CTFArrowTimer = jjGameTicks + 210;
			}
		}
	}
}

bool onDrawPlayerTimer(jjPLAYER@ play, jjCANVAS@ canvas) {
	if (play.fly == FLIGHT::AIRBOARD) {
      	canvas.drawString(
			jjSubscreenWidth - 75,
	      	jjSubscreenHeight - 284,
	      	"" + (play.timerTime > 0? (play.timerTime + 70) / 70 : 0),
	      	STRING::LARGE,
	      	STRING::PALSHIFT,
	      	play.timerTime > 3*70?
	      	24 :
	      	jjGameTicks % 28 > 14?
	      	-40 :
	      	-24
		);
		
		canvas.drawSprite(
			jjSubscreenWidth - 92,
			jjSubscreenHeight - 280,
			ANIM::PICKUPS,
			36, 
			jjGameTicks / 6 % 8
		);
	}
	return true;
}

bool onDrawAmmo(jjPLAYER@ play, jjCANVAS@ canvas) {
	if (controllingRedeemer) {
		canvas.drawString(
			jjSubscreenWidth - 480,
			jjSubscreenHeight - 450,
			"Redeemer!",
			STRING::MEDIUM,
			STRING::NORMAL
		);
		canvas.drawString(
			jjSubscreenWidth - 496,
			jjSubscreenHeight - 422,
			"Redeemer pos " + int(xPos / 32) + "," + int(yPos / 32),
			STRING::SMALL,
			STRING::NORMAL
		);
		canvas.drawString(
			jjSubscreenWidth - 624,
			jjSubscreenHeight - 406,
			"|Use the |||movement keys |||||to rotate the missile",
			STRING::SMALL,
			STRING::NORMAL
		);
		canvas.drawString(
			jjSubscreenWidth - 625,
			jjSubscreenHeight - 390,
			"|Press |||FIRE |||||to detonate the missile in mid-air",
			STRING::SMALL,
			STRING::NORMAL
		);
		if (warning) {
			canvas.drawString(
				jjSubscreenWidth - 550,
				jjSubscreenHeight - 374,
				"||WARNING: YOU ARE IN RANGE!",
				STRING::SMALL,
				STRING::NORMAL
			);
		}
		if (!jjLowDetail && jjGameTicks % 2 == 0) {
			canvas.drawString(
				jjSubscreenWidth - 132,
				jjSubscreenHeight - 46,
				"REC",
				STRING::MEDIUM,
				STRING::NORMAL
			);
			canvas.drawSprite(
				jjSubscreenWidth - 146,
				jjSubscreenHeight - 45,
				ANIM::VINE,
				0,
				0,
				0,
				SPRITE::NORMAL
			);
		}
	}
	return controllingRedeemer;
}

void onFunction0(jjPLAYER@ play) {
	play.showText("@@@@Skyward Showdown@Created by PurpleJazz of XLM (2009-2017)@Tileset by BlurredD@np: Kevin Riepl - Skyscraper [2:01]");
}