Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Find It Out (Single Player) | Superjazz | Single player | 9.1 |
const bool MLLESetupSuccessful = MLLE::Setup(); ///@MLLE-Generated
#include "MLLE-Include-1.6.asc" ///@MLLE-Generated
#pragma require "Fio4_a-MLLE-Data-1.j2l" ///@MLLE-Generated
#pragma require "wbrg.j2t" ///@MLLE-Generated
#pragma require "Fio4_a.j2l" ///@MLLE-Generated
#include "Fio_common.asc"
#include "Fio_cutscene.asc"
#include "Fio_drawing.asc"
#include "Fio_entities.asc"
#include "Fio_globals.asc"
#include "Fio_utils.asc"
enum Cutscene { CUTSCENE_NONE, CUTSCENE_INTRO, CUTSCENE_INTERLUDE };
// Requires ANIM::WITCH to be loaded or a Witch event present in the level
// Level-based implementation with custom texts displayed
class PossessedRock : jjBEHAVIORINTERFACE {
float xOrg;
float yOrg;
float transitionElapsed = 0;
float transitionLength = 70;
float transitionSpeedX;
float transitionSpeedY;
PossessedRock(jjOBJ@ obj) {
xOrg = obj.xOrg;
yOrg = obj.yOrg;
obj.behavior = this;
obj.deactivates = false;
obj.playerHandling = HANDLING::SPECIAL;
obj.scriptedCollisions = true;
}
void onBehave(jjOBJ@ obj) override {
if (obj.freeze > 0 && !hasRockFreezeTextBeenShown) {
fioDraw::doShowText(3);
hasRockFreezeTextBeenShown = true;
}
switch (obj.playerHandling) {
case HANDLING::SPECIAL:
obj.behave(BEHAVIOR::BIGOBJECT);
break;
case HANDLING::SPECIALDONE:
obj.behave(BEHAVIOR::EVA);
if (transitionElapsed > 0) {
transitionElapsed--;
moveTowardsOrigin(obj);
} else {
obj.freeze = 0;
obj.playerHandling = HANDLING::SPECIAL;
// Just to double check
obj.xPos = xOrg;
obj.yPos = yOrg;
}
break;
}
}
void onDraw(jjOBJ@ obj) {
if (obj.playerHandling == HANDLING::SPECIALDONE) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::BLEND_DISSOLVE, 128);
jjDrawRotatedSprite(obj.xPos + 20, obj.yPos - 36, ANIM::WITCH, 1, 55, 512, 2, 2, SPRITE::BLEND_DISSOLVE, 128);
} else if (obj.freeze <= 0) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::TINTED, 24);
jjDrawRotatedSprite(obj.xPos + 20, obj.yPos - 36, ANIM::WITCH, 1, 55, 512, 2, 2);
}
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
// Only when hit by a special move or a buttstomp
if (@bullet !is null) {
bullet.state = STATE::EXPLODE;
} else if (@player !is null && (force == -1 || force == 1)) {
if (!hasRockReturnTextBeenShown) {
fioDraw::doShowText(2);
hasRockReturnTextBeenShown = true;
}
// Set the object's platform behavior to 0 to ensure that the game no longer thinks that the player is standing on the rock when the behavior changes
// (and walk on air, because it seems that the platform property is used to determine that)
obj.clearPlatform();
obj.playerHandling = HANDLING::SPECIALDONE;
transitionElapsed = transitionLength;
float xDistance = xOrg - obj.xPos;
float yDistance = yOrg - obj.yPos;
transitionSpeedX = xDistance / transitionLength;
transitionSpeedY = yDistance / transitionLength;
}
return true;
}
// Required to preserve the object stacking behavior on top of each other with custom behavior classes
bool onIsSolid(jjOBJ@ obj) {
return true;
}
private void moveTowardsOrigin(jjOBJ@ obj) {
obj.xPos += transitionSpeedX;
obj.yPos += transitionSpeedY;
}
}
const float DURATION_FADE_TOTAL = CUTSCENE_SECOND * 4;
const float DURATION_FADE_BLACKOUT = CUTSCENE_SECOND * 2;
const float DURATION_INTRO_SCROLL_FAST = CUTSCENE_SECOND * 3;
const float DURATION_INTRO_SCROLL_SLOW = CUTSCENE_SECOND * 2;
const float INTERLUDE_X = TILE * 216;
const float INTERLUDE_Y = TILE * 150;
const float INTRO_END_Y = TILE * 101 + 8;
const float INTRO_MID_Y = TILE * 91;
const float INTRO_START_Y = TILE * 11;
const float INTRO_X = TILE * 103;
const float PLATFORM_OFFSET = 26;
const float RABBIT_DIZZY_DURATION = CUTSCENE_SECOND * 2;
const float RABBIT_MIND_STONE_DURATION = CUTSCENE_SECOND * 8;
const float RABBIT_ROLL_DURATION = CUTSCENE_SECOND * 6;
const float RABBIT_STILL_DURATION_INTRO = CUTSCENE_SECOND * 5 - 22;
const float RABBIT_STILL_DURATION_INTERLUDE = CUTSCENE_SECOND * 7 - 22;
const float RABBIT_WARP_Y = TILE * 97;
const string NEXT_LEVEL_FILENAME = "Fio4_x.j2l";
const array<ArmoryItem@> ARMORY_ITEMS = {
ArmoryItem(0, "||||Bouncer Power up@+ 20 ammo", 20, 52, ANIM::PICKUPS, 61, 0, @fio::sellArmoryItemBouncerPU),
ArmoryItem(1, "||||Toaster Power up@+20 ammo", 20, 48, ANIM::PICKUPS, 65, 0, @fio::sellArmoryItemToasterPU),
ArmoryItem(2, "||||Pepperspray Power up@+20 ammo", 20, 48, ANIM::PICKUPS, 66, 0, @fio::sellArmoryItemPeppersprayPU),
ArmoryItem(3, "||||Freezer Power up@+20 ammo", 12, 48, ANIM::PICKUPS, 62, 0, @fio::sellArmoryItemFreezerPU),
ArmoryItem(4, "||||+15 Seeker ammo", 25, 48, ANIM::AMMO, 37, 1, @fio::sellArmoryItemSeekerAmmo),
ArmoryItem(5, "", 15, 44, ANIM::PICKUPS, 72, 5, @fio::sellArmoryItemInvincibility, @fio::canBuyInvincibility), // Text updated later when currentGameSession has been loaded
ArmoryItem(6, "", 10, 56, ANIM::PICKUPS, 21, 0, @fio::sellArmoryItemPocketCarrot, @fio::canBuyPocketCarrot) // Text updated later when currentGameSession has been loaded
};
uint8 activeCutscene = uint8(CUTSCENE_NONE);
bool isMindStoneVisible = false;
bool hasFirstTriggerCrateBeenDestroyed = false;
bool hasIceSourceTextBeenShown = false;
bool hasInterludeCutsceneBeenShown = false;
bool hasRockFreezeTextBeenShown = false;
bool hasRockReturnTextBeenShown = false;
ANIM::Set playerAnimSet;
CharacterWithMindStone@ character;
array<Platform@> platforms;
array<Checkpoint@> fio4aCheckpoints = {
Checkpoint(0, INTRO_X, INTRO_END_Y),
Checkpoint(1, INTERLUDE_X, INTERLUDE_Y),
Checkpoint(2, TILE * 234, TILE * 209),
Checkpoint(3, TILE * 72, TILE * 193)
};
array<string> questTexts = {
fio::getQuestText(10, 15, 10000),
fio::getQuestTextComplete(10000),
fio::getQuestTextPerfect(5000)
};
array<string> texts = {
"|Five more gates? Where are the switches and how to get up...Wait what, floating platforms???",
"||Greetings mortal! Meet us, the possessed rocks! If you want us to get out of your way, just give us a punch and we will obey.",
"||Ack! Back to my rest!",
"||ARGH! THAT'S COLD!",
"|What's this burrow about? Doesn't seem like I can go this way without getting hurt.", // 4
"|I guess my only way ahead is to get over that ledge up there somehow.",
"|This seems like a good source of ice! I wonder what can I use it for. Hmm...",
"|I can't even see the bottom of the pit below. I...must...not...fall now...",
"|Hmm...I sense mystic energies. Perhaps I could use the energies for my destination.",
"|I wonder if that wall is destructible..."
};
array<string> cutsceneTextsIntro = {
"||||As the statue of curses cracks down into pieces, you start to suffer a familiar kind of pain, knowing what is happening yet unaware of where you will end.",
"||||After a short while that felt like an eternity in pain, your surroundings are quite different once again.",
"", // Empty for focus on visuality
"", // Empty for focus on visuality
"|Now what is this place? Did I get all the curses from the statue on me?",
"||||You take your mindstone into your hand, trying to get a contact to Nicholas, but you cannot hear anything.",
"|I'll have to get moving and get an understanding of this place. Hopefully I can get a contact to Nicholas later..."
};
array<string> cutsceneTextsInterlude = {
"||||After being warped deeper into the darkness, the mindstone that you received from Nicholas starts to glow, to your surprise...",
"||||You carefully focus your attention on the mindstone before moving forward. You finally hear the voice of Nicholas in your head again, although weaker than before...",
"|||Where are you? I sense a weakness in the energies guarding my cell, but I cannot break free with my current powers just yet.",
"|I have no idea. I brought down the statue of curses as you requested. Then suddenly I got myself summoned into a dark place once again.",
"|I wouldn't know how to describe this place anyway, it's quite dark, but also chillier than the places I've visited previously.",
"|I recall you telling me that you would summon me back to your place after tearing down the statue of curses. Weren't you the one who summoned me here?",
"|||I'm suspecting that whoever destroys the statue of curses, will get themselves summoned to the realm of darkness by the spirits right away...",
"|||I think I have overestimated my powers. Even with the statue of curses destroyed, I cannot help you right now. You'll have to find your way to me.",
"|||Only then can we both find a way out of this place, but that may require obtaining my powers back in some way.",
"|||It may be that a part of my powers are possessed by someone who rules this prison region. You may have to find that someone.",
"|Easier said than done! But I won't give up. I will find my way there. Just hold on a bit longer!"
};
void drawIceSource(jjCANVAS@ canvas) {
canvas.drawRotatedSprite(TILE * 223.5, TILE * 107, ANIM::AMMO, 82, 8, jjGameTicks % 1024, 2, 2, SPRITE::BLEND_NORMAL, 192);
}
void drawMindStoneAtPlayerPos(jjCANVAS@ canvas) {
canvas.drawTile(int(play.xPos) + character.mindStoneX, int(play.yPos) + character.mindStoneY, 965);
canvas.drawTile(int(play.xPos) + character.mindStoneX, int(play.yPos) + character.mindStoneY + TILE, 975);
}
void endCutsceneIntro() {
fioCut::endCutscene(INTRO_X, INTRO_END_Y);
fioCut::isMindstoneCommunicationRendered = false;
isMindStoneVisible = false;
play.lighting = LIGHTING_TWILIGHT;
activeCutscene = CUTSCENE_NONE;
checkpoints[0].setReached();
fioUtils::releasePlayer();
}
void endCutsceneInterlude() {
fioCut::endCutscene(INTERLUDE_X, INTERLUDE_Y);
fioCut::isMindstoneCommunicationRendered = false;
isMindStoneVisible = false;
play.lighting = LIGHTING_TWILIGHT;
activeCutscene = CUTSCENE_NONE;
fioUtils::releasePlayer();
}
int getRemainingGateTriggerCrateAmount() {
int count = 0;
for (int i = 2; i < 7; ++i) {
if (!jjTriggers[i]) {
count++;
}
}
return count;
}
void initiatePlatformMovement() {
for (uint i = 0; i < platforms.length(); i++) {
platforms[i].obj.state = STATE::FADEIN;
}
}
void initializeIntro() {
fioCut::initializeCutscene(@processTickEvents, cutsceneTextsIntro);
fioCut::createEventFade(DURATION_FADE_TOTAL, DURATION_FADE_BLACKOUT, false, true);
fioCut::setTickEventsProcessed(true);
play.noFire = true;
play.cameraFreeze(INTRO_X, INTRO_START_Y, true, true);
activeCutscene = CUTSCENE_INTRO;
}
void initializeInterludeAnimationChain() {
// 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
const array<fioCut::Animation@> animationsInterludeRabbit = {
fioCut::Animation(RABBIT_STILL_DURATION_INTERLUDE,
INTERLUDE_X, INTERLUDE_Y,
INTERLUDE_X, INTERLUDE_Y,
0, 1, 1, playerAnimSet, character.idleAnimation, character.idleFrame, character.idleFrame, 1), // Framerate doesn't really matter here but w/e
fioCut::Animation(16,
INTERLUDE_X, INTERLUDE_Y,
INTERLUDE_X, INTERLUDE_Y,
0, 1, 1, playerAnimSet, character.digAnimation, character.digFrameStart, character.digFrameEnd, 2, 1),
fioCut::Animation(CUTSCENE_SECOND * 76 - 3,
INTERLUDE_X, INTERLUDE_Y,
INTERLUDE_X, INTERLUDE_Y,
0, 1, 1, playerAnimSet, character.withMindStoneAnimation, character.withMindStoneFrame, character.withMindStoneFrame, 1),
fioCut::Animation(16,
INTERLUDE_X, INTERLUDE_Y,
INTERLUDE_X, INTERLUDE_Y,
0, 1, 1, playerAnimSet, character.digAnimation, character.digFrameEnd, character.digFrameStart, 2, 1, true),
fioCut::Animation(CUTSCENE_SECOND,
INTERLUDE_X, INTERLUDE_Y,
INTERLUDE_X, INTERLUDE_Y,
0, 1, 1, playerAnimSet, character.idleAnimation, character.idleFrame, character.idleFrame, 1)
};
fioCut::createAnimationChain(animationsInterludeRabbit);
}
void initializeIntroAnimationChain() {
// 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
const array<fioCut::Animation@> animationsIntroRabbit = {
fioCut::Animation(RABBIT_ROLL_DURATION,
TILE * 104, TILE * 8,
TILE * 104, TILE * 8,
0, 1, 1, playerAnimSet, RABBIT::ROLLING, 0, 7, FRAME_RATE_INTRO_RABBIT),
fioCut::EmptyAnimation(CUTSCENE_SECOND * 8),
fioCut::Animation(10,
INTRO_X, RABBIT_WARP_Y,
INTRO_X, RABBIT_WARP_Y,
0, 1, 1, playerAnimSet, RABBIT::TELEPORTFALL, 0, 7, 2, 1),
fioCut::Animation(15,
INTRO_X, RABBIT_WARP_Y,
INTRO_X, INTRO_END_Y,
0, 1, 1, playerAnimSet, RABBIT::TELEPORTFALLING, 0, 4, 2),
fioCut::Animation(10,
INTRO_X, INTRO_END_Y,
INTRO_X, INTRO_END_Y,
0, 1, 1, playerAnimSet, RABBIT::BUTTSTOMPLAND, 0, 6, 2, 1),
fioCut::Animation(RABBIT_DIZZY_DURATION,
INTRO_X, INTRO_END_Y,
INTRO_X, INTRO_END_Y,
0, 1, 1, playerAnimSet, RABBIT::STONED, 0, playerAnimSet == ANIM::LORI ? 11 : 7, FRAME_RATE_INTRO_RABBIT),
fioCut::Animation(RABBIT_STILL_DURATION_INTRO,
INTRO_X, INTRO_END_Y,
INTRO_X, INTRO_END_Y,
0, 1, 1, playerAnimSet, character.idleAnimation, character.idleFrame, character.idleFrame, 1), // Framerate doesn't really matter here but w/e
fioCut::Animation(16,
INTRO_X, INTRO_END_Y,
INTRO_X, INTRO_END_Y,
0, 1, 1, playerAnimSet, character.digAnimation, character.digFrameStart, character.digFrameEnd, 2, 1),
fioCut::Animation(CUTSCENE_SECOND * 13 - 3,
INTRO_X, INTRO_END_Y,
INTRO_X, INTRO_END_Y,
0, 1, 1, playerAnimSet, character.withMindStoneAnimation, character.withMindStoneFrame, character.withMindStoneFrame, 1),
fioCut::Animation(16,
INTRO_X, INTRO_END_Y,
INTRO_X, INTRO_END_Y,
0, 1, 1, playerAnimSet, character.digAnimation, character.digFrameEnd, character.digFrameStart, 2, 1, true),
fioCut::Animation(CUTSCENE_SECOND,
INTRO_X, INTRO_END_Y,
INTRO_X, INTRO_END_Y,
0, 1, 1, playerAnimSet, character.idleAnimation, character.idleFrame, character.idleFrame, 1)
};
fioCut::createAnimationChain(animationsIntroRabbit);
}
void initializePlatforms() {
platforms = array<Platform@>(0);
// The x argument should represent the location of the left edge of the platform
// and the y argument should represent the top part of the platform
array<array<Node@>> nodeSets = {
{
Node(TILE * 102, TILE * 88 + PLATFORM_OFFSET),
Node(TILE * 102, TILE * 99 + PLATFORM_OFFSET)
},
{
Node(TILE * 103, TILE * 63 + PLATFORM_OFFSET),
Node(TILE * 96, TILE * 59 + PLATFORM_OFFSET),
Node(TILE * 96, TILE * 68 + PLATFORM_OFFSET),
Node(TILE * 97, TILE * 81 + PLATFORM_OFFSET),
Node(TILE * 106, TILE * 84 + PLATFORM_OFFSET),
Node(TILE * 117, TILE * 81 + PLATFORM_OFFSET),
Node(TILE * 117, TILE * 59 + PLATFORM_OFFSET)
},
{
Node(TILE * 164, TILE * 61 + PLATFORM_OFFSET),
Node(TILE * 164, TILE * 74 + PLATFORM_OFFSET)
},
{
Node(TILE * 188, TILE * 77 + PLATFORM_OFFSET),
Node(TILE * 188, TILE * 85 + PLATFORM_OFFSET)
},
{
Node(TILE * 176, TILE * 24 + PLATFORM_OFFSET), // 5th
Node(TILE * 182, TILE * 21 + PLATFORM_OFFSET),
Node(TILE * 194, TILE * 23 + PLATFORM_OFFSET),
Node(TILE * 194, TILE * 32 + PLATFORM_OFFSET),
Node(TILE * 188, TILE * 34 + PLATFORM_OFFSET),
Node(TILE * 178, TILE * 36 + PLATFORM_OFFSET)
},
{
Node(TILE * 141, TILE * 102 + PLATFORM_OFFSET),
Node(TILE * 141, TILE * 113 + PLATFORM_OFFSET)
},
{
Node(TILE * 180, TILE * 209 + PLATFORM_OFFSET),
Node(TILE * 174, TILE * 215 + PLATFORM_OFFSET)
},
{
Node(TILE * 166, TILE * 211 + PLATFORM_OFFSET),
Node(TILE * 172, TILE * 217 + PLATFORM_OFFSET)
},
{
Node(TILE * 165, TILE * 224 + PLATFORM_OFFSET),
Node(TILE * 171, TILE * 218 + PLATFORM_OFFSET)
},
{
Node(TILE * 163, TILE * 224 + PLATFORM_OFFSET), // 10th
Node(TILE * 157, TILE * 218 + PLATFORM_OFFSET)
},
{
Node(TILE * 150, TILE * 206 + PLATFORM_OFFSET),
Node(TILE * 150, TILE * 218 + PLATFORM_OFFSET)
},
{
Node(TILE * 140, TILE * 218 + PLATFORM_OFFSET),
Node(TILE * 148, TILE * 218 + PLATFORM_OFFSET)
},
{
Node(TILE * 103, TILE * 208 + PLATFORM_OFFSET),
Node(TILE * 103, TILE * 220 + PLATFORM_OFFSET)
},
{
Node(TILE * 39, TILE * 205 + PLATFORM_OFFSET),
Node(TILE * 39, TILE * 196 + PLATFORM_OFFSET)
},
{
Node(TILE * 28, TILE * 195 + PLATFORM_OFFSET), // 15th
Node(TILE * 20, TILE * 195 + PLATFORM_OFFSET),
Node(TILE * 20, TILE * 184 + PLATFORM_OFFSET),
Node(TILE * 28, TILE * 184 + PLATFORM_OFFSET)
}
};
array<float> platformSpeeds = {
1.5,
2.5,
2.0,
1.0,
2.5, // 5th
1.5,
1.5,
1.5,
1.5,
1.5, // 10th
2.0,
1.5,
2.0,
2.5,
2.5 // 15th
};
array<uint16> tileIds = {
50, 56, 60, 66
};
for (uint i = 0; i < nodeSets.length(); i++) {
platforms.insertLast(
Platform(
jjObjects[jjAddObject(OBJECT::PINKPLATFORM, nodeSets[i][0].x, nodeSets[i][0].y)],
nodeSets[i],
4, // renderOffsetY
platformSpeeds[i],
tileIds
)
);
}
}
void initializePossessedRocks() {
PossessedRock(jjObjects[jjAddObject(OBJECT::BIGROCK, TILE * 192, TILE * 115.5)]);
PossessedRock(jjObjects[jjAddObject(OBJECT::BIGROCK, TILE * 198, TILE * 115.5)]);
PossessedRock(jjObjects[jjAddObject(OBJECT::BIGROCK, TILE * 220, TILE * 102.5)]);
PossessedRock(jjObjects[jjAddObject(OBJECT::BIGROCK, TILE * 228, TILE * 102.5)]);
PossessedRock(jjObjects[jjAddObject(OBJECT::BIGROCK, TILE * 236, TILE * 102.5)]);
PossessedRock(jjObjects[jjAddObject(OBJECT::BIGROCK, TILE * 236, TILE * 96.5)]);
if (play.charOrig == CHAR::LORI) {
PossessedRock(jjObjects[jjAddObject(OBJECT::BIGROCK, TILE * 240, TILE * 102.5)]);
}
if (jjDifficulty < 1) { // Easy
PossessedRock(jjObjects[jjAddObject(OBJECT::BIGROCK, TILE * 232, TILE * 123)]);
}
}
// Required for each level
bool onCheat(string &in cheat) {
return fio::handleCheat(cheat, NEXT_LEVEL_FILENAME);
}
// Required for each level
bool onDrawHealth(jjPLAYER@ play, jjCANVAS@ canvas) {
fioDraw::animateHud();
fioDraw::drawHud(play, canvas, activeCutscene != CUTSCENE_NONE);
if (shouldShowRemainingGateTriggerCrates()) {
canvas.drawString(jjSubscreenWidth - 48, 40, "" + getRemainingGateTriggerCrateAmount() + "x", STRING::MEDIUM, centeredText);
canvas.drawResizedSprite(jjSubscreenWidth - 16, 40, ANIM::PICKUPS, 52, 0, 0.75, 0.75);
}
if (activeCutscene != CUTSCENE_NONE) {
fioCut::drawCutscene(canvas, centeredText);
}
if (isPlayerInArmory) {
fioDraw::drawArmoryInterface(canvas);
}
return activeCutscene != CUTSCENE_NONE;
}
void onDrawLayer4(jjPLAYER@ play, jjCANVAS@ canvas) {
if (activeCutscene != CUTSCENE_NONE) {
fioCut::renderAnimations(canvas);
if (isMindStoneVisible) {
drawMindStoneAtPlayerPos(canvas);
}
}
fio::renderCommon(play, canvas);
fioDraw::drawArmoryAtPos(canvas, TILE * 79.5, TILE * 172.5); // Offset with +0.5 xTiles and +0.5 yTiles
drawIceSource(canvas);
}
bool onDrawLives(jjPLAYER@ play, jjCANVAS@ canvas) {
return true;
}
bool onDrawScore(jjPLAYER@ play, jjCANVAS@ canvas) {
return activeCutscene != CUTSCENE_NONE;
}
void onFunction0() {
fioDraw::doShowOptionalQuest(0);
}
void onFunction1() {
play.lighting = LIGHTING_TWILIGHT;
}
void onFunction2() {
fioDraw::doShowText(1);
}
void onFunction3() {
fioDraw::doShowText(4);
}
void onFunction4() {
fioDraw::doShowText(5);
}
void onFunction5() {
if (play.ammo[3] < 99) {
play.ammo[3] = 99;
}
if (!hasIceSourceTextBeenShown) {
fioDraw::doShowText(6);
hasIceSourceTextBeenShown = true;
}
}
void onFunction6() {
play.warpToTile(216, 150);
if (!checkpoints[1].isReached()) {
checkpoints[1].setReached();
}
}
void onFunction7() {
play.lighting = LIGHTING_TWILIGHT;
if (!hasInterludeCutsceneBeenShown) {
isPlayerUnableToMove = true;
fioCut::initializeCutscene(@processTickEvents, cutsceneTextsInterlude);
activeCutscene = CUTSCENE_INTERLUDE;
hasInterludeCutsceneBeenShown = true;
}
}
void onFunction8(bool show) {
if (show) {
play.noFire = true;
isPlayerInArmory = true;
} else {
play.noFire = false;
isPlayerInArmory = false;
}
}
void onFunction9() {
play.lighting = LIGHTING_TWILIGHT;
if (!checkpoints[2].isReached()) {
checkpoints[2].setReached();
}
}
void onFunction10() {
fioDraw::doShowText(7);
}
void onFunction11() {
fioDraw::doShowText(8);
}
void onFunction12() {
fio::handleLevelCycle(NEXT_LEVEL_FILENAME, true);
}
void onFunction13() {
fioDraw::doShowText(9);
}
void onFunction14() {
play.lighting = LIGHTING_TWILIGHT;
if (!checkpoints[3].isReached()) {
checkpoints[3].setReached();
}
}
void onLevelBegin() {
@character = fio::getCharacterWithMindStoneForPlayer(play);
initializeIntro();
initializePlatforms();
initializePossessedRocks();
}
// Required for each level
void onLevelLoad() {
initializeGlobals(fio4aCheckpoints, 10, 10000, 5000);
fioDraw::initializeDrawing(texts, questTexts, true);
playerAnimSet = fio::getAnimSetForPlayer(jjLocalPlayers[0]);
// Re-assignment via static declaration
armoryItems = ARMORY_ITEMS;
// Global indice
armoryItemIndexInvincibility = 5;
armoryItemIndexPocketCarrot = 6;
armoryItems[armoryItemIndexInvincibility].text = fio::getInvincibilityItemText();
armoryItems[armoryItemIndexPocketCarrot].text = fio::getPocketCarrotItemText();
mindstoneCommunicationTileIds = array<uint16>(5);
mindstoneCommunicationTileIds[0] = 960;
mindstoneCommunicationTileIds[1] = 969;
mindstoneCommunicationTileIds[2] = 970;
mindstoneCommunicationTileIds[3] = 979;
mindstoneCommunicationTileIds[4] = 980;
jjAnimSets[ANIM::WITCH].load();
}
// Required for each level
void onLevelReload() {
reloadGlobals();
fioDraw::initializeDrawing(texts, questTexts, true);
if (fio::handleLevelReload()) {
activeCutscene = CUTSCENE_NONE;
} else {
initializeIntro();
}
initializePlatforms();
initializePossessedRocks();
if (jjTriggers[1]) {
initiatePlatformMovement();
}
}
// Required for each level
void onMain() {
fio::controlPressedKeys();
fioDraw::controlHud();
if (!hasFirstTriggerCrateBeenDestroyed && jjTriggers[1]) {
hasFirstTriggerCrateBeenDestroyed = true;
fioDraw::doShowText(0);
initiatePlatformMovement();
}
}
// Required for each level
void onPlayer(jjPLAYER@ play) {
fio::handlePlayer(play);
fio::controlQuest();
if (activeCutscene != CUTSCENE_NONE) {
fioCut::run();
if (!fioCut::isTickEventsProcessed()) {
processTickEvents(play);
fioCut::setTickEventsProcessed(true);
}
}
}
void onPlayerInput(jjPLAYER@ play) {
fio::controlArmoryInput(play);
fio::controlPlayerInput(play, activeCutscene != CUTSCENE_NONE);
if (activeCutscene != CUTSCENE_NONE) {
fioCut::controlPlayerInput(play);
if (fioCut::isCutsceneSkipInitiatedAfterDelay(play)) {
fioCut::setCutsceneSkipInitiated();
if (activeCutscene == CUTSCENE_INTRO) {
endCutsceneIntro();
} else if (activeCutscene == CUTSCENE_INTERLUDE) {
endCutsceneInterlude();
}
}
}
}
void onRoast(jjPLAYER@ victim, jjPLAYER@ killer) {
fio::saveTriggerStates();
asPlay.savePlayerProperties(play);
}
void processCutsceneIntro(jjPLAYER@ play) {
switch(uint(fioCut::getElapsedCutscene())) {
case CUTSCENE_SECOND * 1:
fioCut::startTextSliding();
isPlayerHiddenAndUnableToMove = true;
break;
case CUTSCENE_SECOND * 4:
play.xPos = TILE * 117;
play.yPos = TILE * 12;
break;
case CUTSCENE_SECOND * 5:
initializeIntroAnimationChain();
break;
case CUTSCENE_SECOND * 14:
fioCut::createEventCameraScroll(DURATION_INTRO_SCROLL_FAST, INTRO_X, INTRO_START_Y,
INTRO_X, INTRO_MID_Y);
play.xPos = TILE * 91;
play.yPos = TILE * 109;
setObjectPresetsDeactivates(false);
break;
case CUTSCENE_SECOND * 17:
fioCut::createEventCameraScroll(DURATION_INTRO_SCROLL_SLOW, INTRO_X, INTRO_MID_Y,
INTRO_X, INTRO_END_Y);
break;
case CUTSCENE_SECOND * 19:
setObjectPresetsDeactivates(true);
play.xPos = INTRO_X;
play.yPos = INTRO_END_Y;
jjSamplePriority(SOUND::COMMON_TELPORT2);
break;
case CUTSCENE_SECOND * 27:
isMindStoneVisible = true;
fioCut::isMindstoneCommunicationRendered = true;
break;
case CUTSCENE_SECOND * 40 - 3:
// Get player out of the ball mode in time
play.ballTime = 0;
isMindStoneVisible = false;
fioCut::isMindstoneCommunicationRendered = false;
break;
case CUTSCENE_SECOND * 41:
fio::increaseCutscenesWatchedIfFastForwardWasNotUsed(fioCut::wasFastForwardUsed);
endCutsceneIntro();
break;
}
}
void processCutsceneInterlude(jjPLAYER@ play) {
switch(uint(fioCut::getElapsedCutscene())) {
case 8:
fioCut::startTextSliding();
isPlayerHiddenAndUnableToMove = true;
// isPlayerRenderedIdle = true;
initializeInterludeAnimationChain();
break;
case CUTSCENE_SECOND * 8 - 32:
isMindStoneVisible = true;
fioCut::isMindstoneCommunicationRendered = true;
break;
case CUTSCENE_SECOND * 83:
// Get player out of the ball mode in time
play.ballTime = 0;
break;
case CUTSCENE_SECOND * 84 - 32:
isMindStoneVisible = false;
fioCut::isMindstoneCommunicationRendered = false;
break;
case CUTSCENE_SECOND * 84 - 6:
fio::increaseCutscenesWatchedIfFastForwardWasNotUsed(fioCut::wasFastForwardUsed);
endCutsceneInterlude();
break;
}
}
void processTickEvents(jjPLAYER@ play) {
switch (activeCutscene) {
case CUTSCENE_INTRO:
processCutsceneIntro(play);
break;
case CUTSCENE_INTERLUDE:
processCutsceneInterlude(play);
break;
}
}
bool shouldShowRemainingGateTriggerCrates() {
if (!jjTriggers[1]) {
return false;
}
for (int i = 2; i < 7; ++i) {
if (!jjTriggers[i]) {
return true;
}
}
return false;
}
// For displaying objects during cutscene when the player isn't close to the camera view
void setObjectPresetsDeactivates(bool deactivates) {
jjObjectPresets[OBJECT::BAT].deactivates = deactivates;
jjObjectPresets[OBJECT::CARROTCRATE].deactivates = deactivates;
jjObjectPresets[OBJECT::DEMON].deactivates = deactivates;
jjObjectPresets[OBJECT::GOLDCOIN].deactivates = deactivates;
jjObjectPresets[OBJECT::GRAPES].deactivates = deactivates;
jjObjectPresets[OBJECT::GUNCRATE].deactivates = deactivates;
jjObjectPresets[OBJECT::RAPIER].deactivates = deactivates;
jjObjectPresets[OBJECT::SANDWICH].deactivates = deactivates;
jjObjectPresets[OBJECT::TRIGGERCRATE].deactivates = deactivates;
}
Jazz2Online © 1999-INFINITY (Site Credits). We have a Privacy Policy. Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats.
Eat your lima beans, Johnny.