Downloads containing Fio6_End.j2as

Downloads
Name Author Game Mode Rating
JJ2+ Only: Find It Out (Single Player)Featured Download Superjazz Single player 8.7 Download file

File preview

const bool MLLESetupSuccessful = MLLE::Setup(); ///@MLLE-Generated
#include "MLLE-Include-1.6.asc" ///@MLLE-Generated
#pragma require "Fio6_End-MLLE-Data-1.j2l" ///@MLLE-Generated
#pragma require "Fio6_End.j2l" ///@MLLE-Generated
#pragma require "Bonus.s3m"
#include "Fio_common.asc"
#include "Fio_cutscene.asc"
#include "Fio_entities.asc"
#include "Fio_globals.asc"

const float CAMERA_FREEZE_DURATION = CUTSCENE_SECOND;
const float CAMERA_Y = TILE * 44;
const float CAMERA_STILL_DURATION = CUTSCENE_SECOND * 34;
const float FADE_DURATION_TOTAL = CUTSCENE_SECOND * 2;
const float FADE_DURATION_BLACKOUT = CUTSCENE_SECOND;
const float FRAME_RATE_RABBIT_DEFAULT = 2;
const float RABBIT_HOME_IDLE_DURATION = CUTSCENE_SECOND * 8;
const float RABBIT_HOME_PARTY_DURATION = CUTSCENE_SECOND * 60;
const float RABBIT_Y = TILE * 44.5;

const int HEADER_DURATION = 580;

const string HEADER_FIRST = "The End!";
const string HEADER_SECOND = "Thanks for playing!";
const string NEXT_LEVEL_FILENAME = "Fio6_Score.j2l";
const string PARTY_MUSIC_FILENAME = "Bonus.s3m";

const array<float> CAMERA_X_NODES = {
	TILE * 60,
	TILE * 192,
	// TILE * 200,
	TILE * 286
};

const array<float> CAMERA_SCROLL_DURATIONS = {
	CUTSCENE_SECOND * 28,
	CUTSCENE_SECOND * 17
};

bool cutsceneSkipInitiated = false;
bool isHeaderRendered = false;

int headerElapsed = 0;
int headerOpacity = MINIMUM_HEADER_OPACITY;

CharacterWithMindStone@ character;

string displayedHeader;

array<string> cutsceneTexts = {
	"||||As Nicholas took you back to your homeland, he also kept his promise of giving you a new home.",
	"||||As an additional gratitude he and his minions also took care to drive away all the lizards from your lands to ensure peace.",
	"||||While approaching your new home, you feel weary, but relieved of all the challenges you've went through. You just wish for a warm bed.",
	"||||But as you are getting closer to your home, you realize something...",
	"|Duh! Looks like Nicholas didn't forget about ordering me a welcome ceremony either. Hello my friends! It's good to see you after a while!",
	"|Wow! What a show you've got! Everyone's even got a gun in hand like me, duh!",
	"|But what an adventure it was! I've been through places hot and cold, but mostly hot ones.",
	"|And on top of that I saved Nicholas. Who knows how important he will be for me, my people and our well-being in the long run.",
	"|Speaking of Nicholas, where is he? I thought he would join in for my housewarming party as well? No? I guess he's up to his own business then...",
	"|Let's rock the party!",
	"", // Empty for focus on visuality
	"", // Empty for focus on visuality
	"Credits:",
	"Made by Superjazz/Vivando of XLM",
	"Tilesets used: Wisetyness by Mirrow, DARKNESS by Mirrow, Where Bad Rabbits Go by Skulg, Carrotus 1 by Epic, HocusBN by Black Ninja, Oasis by Blade, "
			+ "Egypt (night) by Agama, Damn + Cold by PurpleJazz, Damn + Dark by PurpleJazz and Inferno 1 by Epic",
	"Music used: Last Sunset by Nighthawk, Neve's Crossing by Alexander Brandon, Fastrack.j2b by Epic, Dark Encounters by Reptile & Sky, Boss2.jb by Epic, "
			+ "Underworld II by Alexander Brandon, ndv-srmt by neil d. voss, Land of wonders by Blue Ion, Flying Indian II by Mystical/Purple, "
			+ "Breath of Fire by Awesome, 13th World by Ceekayed (AKA Crimson King), unreal add-on (enigma) by basehead, Empty Forest by Gnosis 1995, "
			+ "Fog polution by Mr. Goblin, Under thine spell by Nightrealm, Warlord Theme by ?, Wargate by Alexander Brandon "
			+ "and Pull Back the Bass by Alexander Brandon",
	"Special thanks to cooba and Snooze!",
	"Also thanks to all betatesters & others giving feedback!"
};

void createCeremonyAnimationsOne() {
	// NOTE TO SELF: DON'T FORGET TO ALSO SET A FINAL VALUE FOR YOUR SPRITEMODE PARAM IN THE ANIMATION CONSTRUCTOR!
	
	for (uint i = 0; i < 3; i++) {
		float offsetX = i == 0 ? -4 : 0;
		float offsetY = i == 0 ? 8 : 0;
		int8 liftJumpFrame = i == 0 ? 7 : 3;
		uint8 spriteModeParam = i == 0 ? 24 : i == 1 ? 40 : 16;
		const array<fioCut::Animation@> animationsCeremony = {
			fioCut::Animation(CUTSCENE_SECOND * 2,
					TILE * 211, RABBIT_Y - 56 + i * 32,
					TILE * 196, RABBIT_Y - 56 + i * 32,
					0, 1, 1, ANIM::SPAZ, RABBIT::STATIONARYJUMP, 0, 2, FRAME_RATE_RABBIT_DEFAULT, 0, false, -1,
					SPRITE::SINGLEHUE, spriteModeParam, spriteModeParam),
			fioCut::Animation(4,
					TILE * 196, RABBIT_Y - 56 + i * 32,
					TILE * 196 - 4, RABBIT_Y - 56 + i * 32,
					0, 1, 1, ANIM::SPAZ, RABBIT::STATIONARYJUMPEND, 0, 1, FRAME_RATE_RABBIT_DEFAULT, 1, false, -1,
					SPRITE::SINGLEHUE, spriteModeParam, spriteModeParam),
			fioCut::Animation(CUTSCENE_SECOND * 10,
					TILE * 196 - 4 + offsetX, RABBIT_Y - 56 + i * 32 + offsetY,
					TILE * 196 - 4 + offsetX, RABBIT_Y - 56 + i * 32 + offsetY,
					0, 1, 1, ANIM::SPAZ, RABBIT::LIFTJUMP, liftJumpFrame, liftJumpFrame, 1, 0, false, -1,
					SPRITE::SINGLEHUE, spriteModeParam, spriteModeParam)
		};
		
		fioCut::createAnimationChain(animationsCeremony);
	}
}

void createCeremonyAnimationsTwo() {
	// NOTE TO SELF: DON'T FORGET TO ALSO SET A FINAL VALUE FOR YOUR SPRITEMODE PARAM IN THE ANIMATION CONSTRUCTOR!
	
	const array<fioCut::Animation@> animationsCeremonyFirst = {
		fioCut::Animation(CUTSCENE_SECOND * 12,
				TILE * 215.5, RABBIT_Y,
				TILE * 215.5, RABBIT_Y,
				0, 1, 1, ANIM::JAZZ, RABBIT::IDLE2, 18, 28, FRAME_RATE_RABBIT_DEFAULT, 0, false, -1,
				SPRITE::PALSHIFT, 8, 8)
	};
	
	fioCut::createAnimationChain(animationsCeremonyFirst);
	
	const array<fioCut::Animation@> animationsCeremonySecond = {
		fioCut::Animation(CUTSCENE_SECOND * 16,
				TILE * 234.5, RABBIT_Y,
				TILE * 215.5, RABBIT_Y,
				0, 1, 1, ANIM::LORI, RABBIT::LOOPY, 0, 11, FRAME_RATE_RABBIT_DEFAULT, 0, false, -1,
				SPRITE::PALSHIFT, 232, 232)
	};
	
	fioCut::createAnimationChain(animationsCeremonySecond);
	
	const array<fioCut::Animation@> animationsCeremonyThird = {
		fioCut::Animation(CUTSCENE_SECOND * 20,
				TILE * 242.5, RABBIT_Y,
				TILE * 242.5, RABBIT_Y,
				0, 1, 1, ANIM::SPAZ, RABBIT::IDLE2, 0, 19, FRAME_RATE_RABBIT_DEFAULT, 0, false, -1,
				SPRITE::PALSHIFT, 8, 8)
	};
	
	fioCut::createAnimationChain(animationsCeremonyThird);
}

// This is becoming fricken hard to read :DDD
void createCeremonyAnimationsThree() {
	// NOTE TO SELF: DON'T FORGET TO ALSO SET A FINAL VALUE FOR YOUR SPRITEMODE PARAM IN THE ANIMATION CONSTRUCTOR!
	
	///////////////////////////////////////////////////////////
	array<fioCut::Animation@> animationsCeremonyFirst = {
		fioCut::Animation(CUTSCENE_SECOND * 75,
				TILE * 283.5, RABBIT_Y,
				TILE * 283.5, RABBIT_Y,
				0, 1, 1, ANIM::JAZZ, RABBIT::FALLLAND, 4, 1, 1, 0, true, 0,
				SPRITE::PALSHIFT, 48, 48)
	};
	
	fioCut::createAnimationChain(animationsCeremonyFirst);
	///////////////////////////////////////////////////////////
	
	///////////////////////////////////////////////////////////
	const array<fioCut::Animation@> animationsCeremonySecond = {
		fioCut::Animation(CUTSCENE_SECOND * 75,
				TILE * 287.5, TILE * 43.5,
				TILE * 287.5, TILE * 43.5,
				0, 1, 1, ANIM::SPAZ, RABBIT::IDLE2, 0, 19, FRAME_RATE_RABBIT_DEFAULT, 0, false, -1,
				SPRITE::PALSHIFT, 16, 16)
	};
	
	fioCut::createAnimationChain(animationsCeremonySecond);
	///////////////////////////////////////////////////////////
	
	///////////////////////////////////////////////////////////
	const array<fioCut::Animation@> animationsCeremonyThird = {
		fioCut::Animation(CUTSCENE_SECOND * 75,
				TILE * 289, RABBIT_Y,
				TILE * 289, RABBIT_Y,
				0, 1, 1, ANIM::LORI, RABBIT::STATIONARYJUMPSTART, 0, 9, FRAME_RATE_RABBIT_DEFAULT, 0, false, -1,
				SPRITE::PALSHIFT, 8, 8)
	};
	
	fioCut::createAnimationChain(animationsCeremonyThird);
	///////////////////////////////////////////////////////////
	
	///////////////////////////////////////////////////////////
	array<fioCut::Animation@> animationsCeremonyFourth = {
		fioCut::Animation(CUTSCENE_SECOND * 75,
				TILE * 286.5, TILE * 35.5,
				TILE * 286.5, TILE * 35.5,
				0, 1, 1, ANIM::JAZZ, RABBIT::FALLLAND, 4, 1, 1, 0, true, -1,
				SPRITE::PALSHIFT, 16, 16)
	};
	
	fioCut::createAnimationChain(animationsCeremonyFourth);
	///////////////////////////////////////////////////////////
	
	///////////////////////////////////////////////////////////
	array<fioCut::Animation@> animationsCeremonyFifth = {
		fioCut::Animation(CUTSCENE_SECOND * 75,
				TILE * 295.5, RABBIT_Y,
				TILE * 295.5, RABBIT_Y,
				0, 1, 1, ANIM::SPAZ, RABBIT::IDLE2, 0, 19, FRAME_RATE_RABBIT_DEFAULT, 0, false, 0,
				SPRITE::PALSHIFT, 8, 8)
	};
	
	fioCut::createAnimationChain(animationsCeremonyFifth);
	///////////////////////////////////////////////////////////
	
	///////////////////////////////////////////////////////////
	const array<fioCut::Animation@> animationsCeremonySixth = {
		fioCut::Animation(CUTSCENE_SECOND * 75,
				TILE * 276, RABBIT_Y,
				TILE * 276, RABBIT_Y,
				0, 1, 1, ANIM::LORI, RABBIT::FALLLAND, 1, 6, FRAME_RATE_RABBIT_DEFAULT, 0, false, 0,
				SPRITE::PALSHIFT, 16, 16)
	};
	
	fioCut::createAnimationChain(animationsCeremonySixth);
	///////////////////////////////////////////////////////////
}

void createBirdAnimations() {
	fioCut::createAnimationChain(getBirdAnimations(false));
	fioCut::createAnimationChain(getBirdAnimations(true));
}

void createMainCharacterAnimationChain() {
	const ANIM::Set playerAnimSet = fio::getAnimSetForPlayer(play);
	
	// Duration, xOrigin, yOrigin, xDestination, yDestination, angle, scaleX, scaleY, animSet, animationId,
	// startingFrame, finalFrame, frameRate, repetitions (optional)
	// REMINDER: DON'T FORGET TO REMOVE THE TRAILING COMMA, SINCE OTHERWISE AS WILL INSERT A NULL HANDLE AFTER THE LAST ACTUAL OBJECT ELEMENT
	
	array<fioCut::Animation@> mainCharacterAnimations = {
		fioCut::Animation(CAMERA_SCROLL_DURATIONS[0],
				CAMERA_X_NODES[0], RABBIT_Y,
				CAMERA_X_NODES[1], RABBIT_Y,
				0, 1, 1, playerAnimSet, RABBIT::RUN1, 0, 7, FRAME_RATE_RABBIT_DEFAULT),
		fioCut::Animation(CUTSCENE_SECOND * 9,
				CAMERA_X_NODES[1], RABBIT_Y,
				CAMERA_X_NODES[1], RABBIT_Y,
				0, 1, 1, playerAnimSet, character.idleAnimation, character.idleFrame, character.idleFrame, 1)
	};
	
	array<fioCut::Animation@> celebrationAnimations = getCelebrationAnimationsForPlayer(playerAnimSet);
	
	for (uint i = 0; i < celebrationAnimations.length(); ++i) {
		mainCharacterAnimations.insertLast(celebrationAnimations[i]);
	}
	
	mainCharacterAnimations.insertLast(fioCut::Animation(CAMERA_SCROLL_DURATIONS[1],
				CAMERA_X_NODES[1], RABBIT_Y,
				CAMERA_X_NODES[2], RABBIT_Y,
				0, 1, 1, playerAnimSet, RABBIT::RUN1, 0, 7, FRAME_RATE_RABBIT_DEFAULT));
				
	mainCharacterAnimations.insertLast(fioCut::Animation(RABBIT_HOME_IDLE_DURATION,
				CAMERA_X_NODES[2], RABBIT_Y,
				CAMERA_X_NODES[2], RABBIT_Y,
				0, 1, 1, playerAnimSet, character.idleAnimation, character.idleFrame, character.idleFrame, 1));
	
	mainCharacterAnimations.insertLast(getPartyAnimationForPlayer());
	
	fioCut::createAnimationChain(mainCharacterAnimations);
}

array<fioCut::Animation@> getBirdAnimations(bool mirrored) {
	array<fioCut::Animation@> birdAnimations;

	for (uint i = 0; i < 10; ++i) {
		if (mirrored) {
			birdAnimations.insertLast(
					fioCut::Animation(CUTSCENE_SECOND * 5,
							TILE * 272, TILE * 38,
							TILE * 301, TILE * 40,
							0, 1, 1, ANIM::SPAZ2, 2, 0, 7, FRAME_RATE_RABBIT_DEFAULT, 0, false, -1));
			birdAnimations.insertLast(
					fioCut::Animation(CUTSCENE_SECOND * 5,
							TILE * 301, TILE * 40,
							TILE * 272, TILE * 38,
							0, 1, 1, ANIM::SPAZ2, 2, 0, 7, FRAME_RATE_RABBIT_DEFAULT, 0, false, 0));
		} else {
			birdAnimations.insertLast(
					fioCut::Animation(CUTSCENE_SECOND * 5,
							TILE * 301, TILE * 38,
							TILE * 272, TILE * 40,
							0, 1, 1, ANIM::SPAZ2, 2, 0, 7, FRAME_RATE_RABBIT_DEFAULT, 0, false, 0));
			birdAnimations.insertLast(
					fioCut::Animation(CUTSCENE_SECOND * 5,
							TILE * 272, TILE * 40,
							TILE * 301, TILE * 38,
							0, 1, 1, ANIM::SPAZ2, 2, 0, 7, FRAME_RATE_RABBIT_DEFAULT, 0, false, -1));
		}
	}
	
	return birdAnimations;
}

array<fioCut::Animation@> getCelebrationAnimationsForPlayer(ANIM::Set playerAnimSet) {
	array<fioCut::Animation@> celebrationAnimations;
	// TOTAL SHOULD BE 5 CUTSCENE_SECONDS - 4 ATM
	if (play.charOrig == CHAR::LORI) {
	
		celebrationAnimations.insertLast(fioCut::Animation(CUTSCENE_SECOND * 3 - 14,
				CAMERA_X_NODES[1], RABBIT_Y,
				CAMERA_X_NODES[1], RABBIT_Y,
				0, 1, 1, playerAnimSet, RABBIT::STATIONARYJUMPSTART, 0, 9, FRAME_RATE_RABBIT_DEFAULT, 5));
		celebrationAnimations.insertLast(fioCut::Animation(CUTSCENE_SECOND * 2 - 14,
				CAMERA_X_NODES[1], RABBIT_Y,
				CAMERA_X_NODES[1], RABBIT_Y,
				0, 1, 1, playerAnimSet, RABBIT::SPRING, 0, 7, FRAME_RATE_RABBIT_DEFAULT, 4));
		celebrationAnimations.insertLast(fioCut::Animation(24,
				CAMERA_X_NODES[1], RABBIT_Y,
				CAMERA_X_NODES[1], RABBIT_Y,
				0, 1, 1, playerAnimSet, RABBIT::FALLLAND, 0, 6, FRAME_RATE_RABBIT_DEFAULT, 1));
				
	} else if (play.charOrig == CHAR::SPAZ) {
	
		celebrationAnimations.insertLast(fioCut::Animation(CUTSCENE_SECOND * 5 - 4,
				CAMERA_X_NODES[1], RABBIT_Y,
				CAMERA_X_NODES[1], RABBIT_Y,
				0, 1, 1, playerAnimSet, RABBIT::IDLE2, 0, 19, FRAME_RATE_RABBIT_DEFAULT, 3));
		
	} else { // JAZZ
		celebrationAnimations.insertLast(fioCut::Animation(CUTSCENE_SECOND * 3 - 4,
				CAMERA_X_NODES[1], RABBIT_Y,
				CAMERA_X_NODES[1], RABBIT_Y,
				0, 1, 1, playerAnimSet, RABBIT::IDLE2, 0, 45, FRAME_RATE_RABBIT_DEFAULT, 1));
		celebrationAnimations.insertLast(fioCut::Animation(CUTSCENE_SECOND * 2,
					CAMERA_X_NODES[1], RABBIT_Y,
					CAMERA_X_NODES[1], RABBIT_Y,
					0, 1, 1, playerAnimSet, RABBIT::FALLLAND, 4, 1, 1, 0, true));
	}
	
	return celebrationAnimations;
}

fioCut::Animation@ getPartyAnimationForPlayer() {
	if (play.charOrig == CHAR::LORI) {
		return fioCut::Animation(RABBIT_HOME_PARTY_DURATION,
				CAMERA_X_NODES[2], RABBIT_Y,
				CAMERA_X_NODES[2], RABBIT_Y,
				0, 1, 1, ANIM::LORI, RABBIT::STATIONARYJUMPSTART, 0, 9, 1, 0, false, -1);
				
	}
	
	if (play.charOrig == CHAR::SPAZ) {
		return fioCut::Animation(RABBIT_HOME_PARTY_DURATION,
				CAMERA_X_NODES[2], RABBIT_Y,
				CAMERA_X_NODES[2], RABBIT_Y,
				0, 1, 1, ANIM::SPAZ, RABBIT::IDLE2, 0, 19, 1, 0);
		
	}
	
	// JAZZ
	return fioCut::Animation(RABBIT_HOME_PARTY_DURATION,
			CAMERA_X_NODES[2], RABBIT_Y,
			CAMERA_X_NODES[2], RABBIT_Y,
			0, 1, 1, ANIM::JAZZ, RABBIT::FALLLAND, 4, 1, 1, 0, true);
}

// Required for each level
bool onCheat(string &in cheat) {
	return fio::handleCheat(cheat, NEXT_LEVEL_FILENAME);
}

bool onDrawHealth(jjPLAYER@ play, jjCANVAS@ canvas) {
	fioCut::drawCutscene(canvas, centeredText);
	
	if (isHeaderRendered) {
		canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight / 4, displayedHeader, STRING::LARGE, centeredText, 0,
				SPRITE::BLEND_NORMAL, headerOpacity);
		
		if (jjGameTicks % 2 == 0) {
			if (headerElapsed < HEADER_DURATION / 2 && headerOpacity < MAXIMUM_HEADER_OPACITY) {
				headerOpacity++;
			} else if (headerOpacity > MINIMUM_HEADER_OPACITY) {
				headerOpacity--;
			}
			
			if (headerElapsed < HEADER_DURATION) {
				headerElapsed++;
			} else {
				isHeaderRendered = false;
			}
		}
	}
	
	return true;
}

void onDrawLayer4(jjPLAYER@ play, jjCANVAS@ canvas) {
	fioCut::renderAnimations(canvas);
}

void onDrawLayer5(jjPLAYER@ play, jjCANVAS@ canvas) {
	canvas.drawSprite(TILE * 194, RABBIT_Y, ANIM::SPAZ, RABBIT::REV1, 0, -1, SPRITE::PALSHIFT, 8);
	canvas.drawSprite(TILE * 194, TILE * 39, ANIM::JAZZ, RABBIT::REV1, 0, -1, SPRITE::PALSHIFT, 16);
	canvas.drawSprite(TILE * 203, TILE * 41, ANIM::LORI, RABBIT::REV1, 0, -1, SPRITE::PALSHIFT, 16);
	canvas.drawSprite(TILE * 256.5, RABBIT_Y, ANIM::SPAZ, RABBIT::REV1, 0, -1, SPRITE::PALSHIFT, 24);
	fioCut::renderAnimations(canvas);
}

bool onDrawLives(jjPLAYER@ play, jjCANVAS@ canvas) {
	return true;
}

bool onDrawScore(jjPLAYER@ play, jjCANVAS@ canvas) {
	return true;
}

void onLevelBegin() {
	initializeGlobals(array<Checkpoint@> = {}); // Not sure why I did it in onLevelBegin again anymore, probably just for debug reasons
	@character = fio::getCharacterWithMindStoneForPlayer(play);
	fioCut::initializeCutscene(@processTickEvents, cutsceneTexts);
	fioCut::createEventFade(FADE_DURATION_TOTAL, FADE_DURATION_BLACKOUT, false, true);
}

void onLevelLoad() {
	jjAnimSets[ANIM::AMMO].load();
}

void onLevelReload() {
	MLLE::ReapplyPalette();
}

void onPlayer(jjPLAYER@ play) {
	if (jjGameTicks == 1) {
		play.noFire = true;
		play.cameraFreeze(CAMERA_X_NODES[0], CAMERA_Y, true, true);
	}
	
	fio::controlPressedKeys();
	runCutscene();
	
	if (!fioCut::isTickEventsProcessed()) {
		processTickEvents(play);
		fioCut::setTickEventsProcessed(true);
	}
}

void onPlayerInput(jjPLAYER@ play) {
	fioCut::controlPlayerInput(play);
	if (fioCut::isCutsceneSkipInitiatedAfterDelay(play)) {
		fioCut::setCutsceneSkipInitiated();
		fio::handleLevelCycle(NEXT_LEVEL_FILENAME, false, true);
	}
}

void processTickEvents(jjPLAYER@ play) {
	switch(uint(fioCut::getElapsedCutscene())) {
		case CUTSCENE_SECOND * 1:
			fioCut::createEventCameraScroll(CAMERA_SCROLL_DURATIONS[0],
					CAMERA_X_NODES[0], CAMERA_Y,
					CAMERA_X_NODES[1], CAMERA_Y);
			createMainCharacterAnimationChain();
			break;
		case CUTSCENE_SECOND * 3:
			fioCut::startTextSliding();
			break;
		case CUTSCENE_SECOND * 35:
			createCeremonyAnimationsOne();
			break;
		case CUTSCENE_SECOND * 43 - 2:
			fioCut::createEventCameraScroll(CAMERA_SCROLL_DURATIONS[1],
					CAMERA_X_NODES[1], CAMERA_Y,
					CAMERA_X_NODES[2], CAMERA_Y);
			createCeremonyAnimationsTwo();
			break;
		case CUTSCENE_SECOND * 56:
			createCeremonyAnimationsThree();
			break;
		case CUTSCENE_SECOND * 64:
			createBirdAnimations();
			break;
		case CUTSCENE_SECOND * 68:
			jjMusicLoad(PARTY_MUSIC_FILENAME);
			jjSetModPosition(5, 0, false);
			break;
		case CUTSCENE_SECOND * 70:
			headerElapsed = 0;
			headerOpacity = MINIMUM_HEADER_OPACITY;
			displayedHeader = HEADER_FIRST;
			isHeaderRendered = true;
			break;
		case CUTSCENE_SECOND * 124:
			headerElapsed = 0;
			headerOpacity = MINIMUM_HEADER_OPACITY;
			displayedHeader = HEADER_SECOND;
			isHeaderRendered = true;
			break;
		case CUTSCENE_SECOND * 128:
			fio::increaseCutscenesWatchedIfFastForwardWasNotUsed(fioCut::wasFastForwardUsed);
			fio::handleLevelCycle(NEXT_LEVEL_FILENAME, false, true);
			break;
	}
}

void runCutscene() {
	fioCut::run();
	
	if (!fioCut::isTickEventsProcessed()) {
		processTickEvents(play);
		fioCut::setTickEventsProcessed(true);
	}
}