Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
![]() |
Diamondus Ultimate![]() |
DoubleGJ | Tileset conversion | 10 | ![]() |
|||
![]() |
Jungle Ultimate![]() |
DoubleGJ | Tileset conversion | 10 | ![]() |
/* ===Demon Dash ranking script v0.6===
Written by Gnegon Galek, rank calculation adjustments by Seren, end transition by SpazElectro
This module also removes the extra lives system on easy mode.
Optionally, you can also set a time limit for the level depending on difficulty.
It works like in JJ1: if time runs out, you lose a life! Fortunately, you can continue from a checkpoint with the timer reset to full.
Hourglass now functions like in JJ1, ditching the pretty much useless player freezing effect.
---PUT IN LEVEL SCRIPT, MERGE WITH SAME FUNCTIONS IF NEEDED:---
const float maxScore = ?; // greatest REALISTICALLY OBTAINABLE score to obtain in the level (do not calculate, playtest)
const int bestTime = ?; // best REALISTICALLY OBTAINABLE level completion time in seconds (don't just blast thru the level with jjinv/jjgod)
const int easyTimer = 0; // leave as 0 for no time limit
const int normalTimer = 0;
const int hardTimer = 84000; // in ticks
const int turboTimer = 63000;
void onLevelLoad() {
initiateRanking();
initFade();
}
void onLevelBegin() {
setTimer(); // can be left out if you don't want a time limit on any difficulty
}
void onLevelReload() {
scoreSeconds = storeScoreSeconds; // maybe there's a way to have this work in cooperative, but I'm out of ideas
}
void onMain() {
if (jjDifficulty == 0) {
oneUpsIntoBlueGems();
}
if ((jjGameTicks % 70) == 0 && !levelOver) { // if used in tandem with DD-Order.asc, it's gonna need "&& CurrentPopup is null" too
scoreSeconds++;
}
rankingSetup();
if (levelOver) updateFade();
}
bool onDrawScore(jjPLAYER@ player, jjCANVAS@ canvas) {
if (levelOver) {
drawFade(player, canvas);
if (rankLine < 6) rankingDisplay(player, canvas);
}
if (rankLine >= 6) return true;
else return false;
}
bool onDrawHealth(jjPLAYER@ player, jjCANVAS@ canvas) {
if (rankLine >= 6) return true;
else return false;
}
bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
if (rankLine >= 6) return true;
else return false;
}
bool onDrawLives(jjPLAYER@ player, jjCANVAS@ canvas) {
if (jjDifficulty == 0) { // "&& CurrentPopup is null" when used with DD-Order.asc
infiniteLives(player, canvas); // can be left out if you don't want to display the life icon at all, like in online co-op
return true;
}
if (rankLine >= 6) return true;
else return false; // or return "CurrentPopup !is null && !CurrentPopup.DrawHUD();" when used with DD-Order.asc
}
bool onCheat(string &in cheat) {
if (levelOver) return true; // avoid bugs caused by getting out of end screen
else return false;
}
void onPlayer(jjPLAYER@ player) {
rankingInterface(player);
}
void onPlayerDraw(jjPLAYERDRAW& draw) {
jjPLAYER@ play = draw.player;
if (isFading) {
draw.sprite = false;
return;
}
}
---CALL THIS FUNCTION WHEN YOU WANT TO END THE LEVEL:---
endLevel(player, warp EOL = false); // must be tied to player that triggered level end!!
*/
#pragma require "children-yay.wav"
#pragma require "party-horn.wav"
#pragma require "wow.wav"
#pragma require "weak-fart.wav"
#pragma require "STVcartoonfade_fade.png"
#pragma offer "DD-Rank.s3m"
///@Event 90=Hourglass |-|Goodies |Hour|Glass
bool levelOver, fanfarePlayed, jinglePlayed, wowPlayed, endLivesGiven, smallScreen, stampPlayed, isFading, warpAnim, exitLeftAnim = false;
int scoreSeconds, storeScoreSeconds, timerMsgCD, rightSlide, topSlide, bottomSlide, gemTotal;
float timeDifference, DEFAULT_FADE_SCALE = 0.0;
float rankStamp = 10.0;
array<int> startingScore(5, 0);
array<int> timeBonus(5, 0);
array<int> hitPenalty(5, -1000); // take into account start of level blink
array<int> textSlide(6, -160);
array<array<int>> displayGems(4, array<int>(3));
const int gemsForExtraLife = 500; // editable in case testing proves that's too much
int rankLine, leftMargin, leftIndent, topMargin, bigLine, smallLine, rankLineCD, levelScore, totalScore, timeBonusDisplay, hitPenaltyDisplay, gemChannel, displayMinutes, displaySeconds, gtfoAnim = 0;
int waitJingle = 400;
const float FADE_SCALE_STEP = 0.05;
float fadeScale = DEFAULT_FADE_SCALE;
void initiateRanking() {
jjSampleLoad(SOUND::INTRO_BLOW, "weak-fart.wav");
jjSampleLoad(SOUND::INTRO_BOEM1, "children-yay.wav");
jjSampleLoad(SOUND::INTRO_BOEM2, "party-horn.wav");
jjSampleLoad(SOUND::INTRO_IFEEL, "wow.wav");
jjObjectPresets[OBJECT::SAVEPOST].behavior = savePost;
for (int i = 0; i < (jjLocalPlayerCount + 1); i++) {
startingScore[i] = jjLocalPlayers[i].score;
}
}
void rankingSetup() {
smallScreen = jjSubscreenWidth <= 400;
leftMargin = int(jjSubscreenWidth / 16);
leftIndent = int(smallScreen ? jjSubscreenWidth / 10 : jjSubscreenWidth / 12);
topMargin = int(jjSubscreenHeight / 12);
bigLine = int(jjSubscreenHeight / 12);
smallLine = int(jjSubscreenHeight / 18);
if (!levelOver) {
rightSlide = int(jjSubscreenWidth * 1.2);
topSlide = int(jjSubscreenHeight / 16) * -1;
bottomSlide = jjSubscreenHeight + int(jjSubscreenHeight / 16);
}
if (levelOver && rankLine > 5) fade();
if (levelOver && rankLineCD > 0) rankLineCD--;
if (jinglePlayed && waitJingle > 0) waitJingle--;
if (waitJingle == 0 && !isFading) jjMusicLoad("DD-Rank.s3m");
if (isFading) jjMusicStop();
}
void rankingDisplay(jjPLAYER@ player, jjCANVAS@ canvas) {
if (topSlide < jjSubscreenHeight / 32) { topSlide += 2; } // we'll get the precise positioning later, mmkay?
if (bottomSlide > jjSubscreenHeight - (jjSubscreenHeight / 32)) { bottomSlide -= 2; } // mirrors line above so don't forget to adjust as well
canvas.drawString(int(ceil(jjSubscreenWidth / 3)), topSlide, "LEVEL COMPLETE", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
canvas.drawString(int(ceil(jjSubscreenWidth / 6)), bottomSlide, "Press Fire or Select to continue", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
if (rightSlide > jjSubscreenWidth * 0.65) { rightSlide -= 8; }
if (displayGems[player.localPlayerID][0] < player.gems[GEM::RED] || displayGems[player.localPlayerID][1] < player.gems[GEM::GREEN] || displayGems[player.localPlayerID][2] < player.gems[GEM::BLUE]) {
gemChannel = jjSampleLooped(jjLocalPlayers[0].xPos, jjLocalPlayers[0].yPos, SOUND::COMMON_PICKUP1, gemChannel);
}
if ((displayGems[player.localPlayerID][0] < player.gems[GEM::RED]) && jjGameTicks % 5 == 0) { displayGems[player.localPlayerID][0]++; }
if ((displayGems[player.localPlayerID][1] < player.gems[GEM::GREEN]) && jjGameTicks % 5 == 0) { displayGems[player.localPlayerID][1]++; }
if ((displayGems[player.localPlayerID][2] < player.gems[GEM::BLUE]) && jjGameTicks % 5 == 0) { displayGems[player.localPlayerID][2]++; }
canvas.drawString(rightSlide, topMargin + smallLine + bigLine, "x " + formatInt(displayGems[player.localPlayerID][0]), smallScreen ? STRING::SMALL : STRING::MEDIUM);
canvas.drawSprite(rightSlide - 24, topMargin + smallLine + bigLine, ANIM::PICKUPS, 22, (jjGameTicks/10) % 7, 0, SPRITE::GEM, 0);
canvas.drawString(rightSlide, topMargin + (smallLine * 2) + (bigLine * 2), "x " + formatInt(displayGems[player.localPlayerID][1]), smallScreen ? STRING::SMALL : STRING::MEDIUM);
canvas.drawSprite(rightSlide - 24, topMargin + (smallLine * 2) + (bigLine * 2), ANIM::PICKUPS, 22, (jjGameTicks/10) % 7, 0, SPRITE::GEM, 1);
canvas.drawString(rightSlide, topMargin + (smallLine * 3) + (bigLine * 3), "x " + formatInt(displayGems[player.localPlayerID][2]), smallScreen ? STRING::SMALL : STRING::MEDIUM);
canvas.drawSprite(rightSlide - 24, topMargin + (smallLine * 3) + (bigLine * 3), ANIM::PICKUPS, 22, (jjGameTicks/10) % 7, 0, SPRITE::GEM, 2);
canvas.drawString(rightSlide, topMargin + (smallLine * 4) + (bigLine * 4), "TOTAL GEMS", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
canvas.drawString(rightSlide, topMargin + (smallLine * 5) + (bigLine * 4), formatInt(displayGems[player.localPlayerID][0] + (displayGems[player.localPlayerID][1] * 5) + (displayGems[player.localPlayerID][2] * 10)), smallScreen ? STRING::SMALL : STRING::MEDIUM);
if (textSlide[0] < leftMargin) textSlide[0] += 8;
else if (textSlide[0] > leftMargin) textSlide[0] = leftMargin; // fix overshooting
canvas.drawString(textSlide[0], topMargin, "Level Score", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
if (levelScore < player.score - startingScore[player.localPlayerID]) levelScore += 100;
else if (levelScore > player.score - startingScore[player.localPlayerID]) levelScore = player.score - startingScore[player.localPlayerID]; // also fix overshooting...
else if (rankLine == 0 && rankLineCD == 0) {
rankLineCD = 60;
rankLine++;
}
canvas.drawString(textSlide[0], topMargin + smallLine, formatInt(levelScore), smallScreen ? STRING::SMALL : STRING::MEDIUM);
if (rankLine >= 1) {
if (textSlide[1] < leftMargin) textSlide[1] += 8;
else if (textSlide[1] > leftMargin) textSlide[1] = int(leftMargin);
levelScore = player.score - startingScore[player.localPlayerID];
canvas.drawString(textSlide[1], topMargin + smallLine + bigLine, "Completion Time", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
canvas.drawString(textSlide[1], topMargin + (smallLine * 2) + bigLine, formatInt(displayMinutes) + ":" + formatInt(displaySeconds, '0', 2), smallScreen ? STRING::SMALL : STRING::MEDIUM);
if (displayMinutes < int(scoreSeconds / 60)) {
displaySeconds++;
if (displaySeconds == 60) {
displayMinutes++;
displaySeconds = 0;
}
}
else if (displaySeconds < scoreSeconds % 60) displaySeconds++;
else if (rankLine == 1 && rankLineCD == 0) {
rankLineCD = 60;
rankLine++;
}
}
if (rankLine >= 2) {
if (textSlide[2] < leftMargin) textSlide[2] += 8;
else if (textSlide[2] > leftMargin) textSlide[2] = leftMargin;
displayMinutes = int(scoreSeconds / 60);
displaySeconds = scoreSeconds % 60;
canvas.drawString(textSlide[2], topMargin + (smallLine * 2) + (bigLine * 2), "Time Bonus", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
if (timeBonusDisplay < timeBonus[player.localPlayerID]) timeBonusDisplay += 100;
else if (timeBonusDisplay > timeBonus[player.localPlayerID]) timeBonusDisplay = timeBonus[player.localPlayerID];
else if (rankLine == 2 && rankLineCD == 0) {
rankLineCD = 60;
rankLine++;
}
canvas.drawString(textSlide[2], topMargin + (smallLine * 3) + (bigLine * 2), formatInt(timeBonusDisplay), smallScreen ? STRING::SMALL : STRING::MEDIUM);
}
if (rankLine >= 3) {
if (textSlide[3] < leftMargin) textSlide[3] = textSlide[3] + 8;
else if (textSlide[3] > leftMargin) textSlide[3] = leftMargin;
timeBonusDisplay = timeBonus[player.localPlayerID];
canvas.drawString(textSlide[3], topMargin + (smallLine * 3) + (bigLine * 3), "Hit Penalty", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
if (hitPenaltyDisplay > hitPenalty[player.localPlayerID] * -1) hitPenaltyDisplay -= 100; // this is always a multiple of 1000 so not doing overshoot check
if (hitPenaltyDisplay == 0 && textSlide[3] == leftMargin && !wowPlayed) {
jjSamplePriority(SOUND::INTRO_IFEEL);
int yoinky = int(jjRandom() % 8 + 8);
for (int i = 0; i < yoinky; i++) {
jjPARTICLE@ particle = jjAddParticle(PARTICLE::STAR);
particle.xPos = player.cameraX + leftMargin + (smallScreen ? jjAnimFrames[jjAnimations[jjAnimSets[ANIM::FONT].firstAnim + 1].firstFrame + 16].width / 2 : jjAnimFrames[jjAnimations[jjAnimSets[ANIM::FONT].firstAnim].firstFrame + 16].width / 2);
particle.yPos = player.cameraY + topMargin + (smallLine * 4) + (bigLine * 3) + (smallScreen ? 8 : 4);
particle.xSpeed = int(jjRandom() % 9 - 4); // don't ask me why it needs to be converted to int. it just does
particle.ySpeed = int(jjRandom() % 9 - 4);
particle.star.angularSpeed = int(jjRandom() % 4 + 1);
particle.star.color = int(jjRandom() % 3 + 64);
particle.star.size = int(jjRandom() % 16 + 24);
}
wowPlayed = true;
}
if (rankLine == 3 && rankLineCD == 0 && hitPenaltyDisplay == hitPenalty[player.localPlayerID] * -1) {
rankLineCD = 60;
rankLine++;
}
canvas.drawString(textSlide[3], topMargin + (smallLine * 4) + (bigLine * 3), formatInt(hitPenaltyDisplay), smallScreen ? STRING::SMALL : STRING::MEDIUM);
}
if (wowPlayed) {
canvas.drawString(leftMargin + leftIndent, topMargin + (smallLine * 4) + (bigLine * 3), "FLAWLESS!!", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
}
if (rankLine >= 4) {
if (textSlide[4] < leftMargin) textSlide[4] += 8;
else if (textSlide[4] > leftMargin) textSlide[4] = leftMargin;
hitPenaltyDisplay = hitPenalty[player.localPlayerID] * -1;
canvas.drawString(textSlide[4], topMargin + (smallLine * 4) + (bigLine * 4), "Total", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
if (totalScore < player.score - startingScore[player.localPlayerID] + timeBonus[player.localPlayerID] - hitPenalty[player.localPlayerID]) totalScore = totalScore + 100;
else if (totalScore > player.score - startingScore[player.localPlayerID] + timeBonus[player.localPlayerID] - hitPenalty[player.localPlayerID]) { totalScore = player.score - startingScore[player.localPlayerID] + timeBonus[player.localPlayerID] - hitPenalty[player.localPlayerID]; }
else if (rankLine == 4 && rankLineCD == 0) {
rankLineCD = 60;
rankLine++;
}
canvas.drawString(textSlide[4], topMargin + (smallLine * 5) + (bigLine * 4), formatInt(totalScore), smallScreen ? STRING::SMALL : STRING::MEDIUM);
displayGems[player.localPlayerID][0] = player.gems[GEM::RED];
displayGems[player.localPlayerID][1] = player.gems[GEM::GREEN];
displayGems[player.localPlayerID][2] = player.gems[GEM::BLUE];
gemTotal = displayGems[player.localPlayerID][0] + (displayGems[player.localPlayerID][1] * 5) + (displayGems[player.localPlayerID][2] * 10);
if (jjDifficulty > 0) {
canvas.drawSprite(int(jjSubscreenWidth * 0.65) + 10, topMargin + (smallLine * 5) + (bigLine * 5), ANIM::PICKUPS, 0, (jjGameTicks/7) % 9);
canvas.drawString(int(jjSubscreenWidth * 0.65) + 32, topMargin + (smallLine * 5) + (bigLine * 5), "x " + formatInt(gemTotal / gemsForExtraLife), smallScreen ? STRING::SMALL : STRING::MEDIUM);
if ((int(gemTotal / gemsForExtraLife) > 0) && !endLivesGiven) {
player.lives = player.lives + int(gemTotal / gemsForExtraLife);
jjPARTICLE@ particle = jjAddParticle(PARTICLE::STRING);
if (particle !is null) {
particle.xPos = player.cameraX + int(jjSubscreenWidth * 0.65) + 10;
particle.yPos = player.cameraY + topMargin + (smallLine * 5) + (bigLine * 5);
particle.xSpeed = (-65536 - int(jjRandom() & 0x3FFF)) / 65536.f; // negative
particle.ySpeed = (-7168 - int(jjRandom() & 0x7FFF)) / -65536.f; // positive
particle.string.text = formatInt(gemTotal / gemsForExtraLife) + "UP!";
}
jjSamplePriority(SOUND::COMMON_HARP1);
endLivesGiven = true;
}
}
}
if (rankLine >= 5) {
if (textSlide[5] < leftMargin) textSlide[5] += 8;
else if (textSlide[5] > leftMargin) textSlide[5] = leftMargin;
totalScore = player.score - startingScore[player.localPlayerID] + timeBonus[player.localPlayerID] - hitPenalty[player.localPlayerID];
canvas.drawString(textSlide[5], topMargin + (smallLine * 5) + (bigLine * 5), "RANK", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
if (rankStamp > 1) rankStamp -= 0.4;
else if (rankStamp < 1) rankStamp = 1; // just in case??
else if (!stampPlayed) {
jjSamplePriority(SOUND::COMMON_LAND1);
stampPlayed = true;
}
if ((player.score - startingScore[player.localPlayerID] + timeBonus[player.localPlayerID] - hitPenalty[player.localPlayerID]) * jjLocalPlayerCount >= maxScore * 1.5) {
canvas.drawResizedSprite(leftIndent, topMargin + (smallLine * 6) + (bigLine * 5), ANIM::FONT, smallScreen ? 0 : 2, 51, rankStamp, rankStamp, SPRITE::PALSHIFT, 232);
if (!fanfarePlayed && rankStamp == 1) {
jjSamplePriority(SOUND::INTRO_BOEM1);
int sploinky = int(jjRandom() % 24 + 24);
for (int i = 0; i < sploinky; i++) {
jjPARTICLE@ particle = jjAddParticle(PARTICLE::STAR);
particle.xPos = player.cameraX + leftIndent + (smallScreen ? jjAnimFrames[jjAnimations[jjAnimSets[ANIM::FONT].firstAnim].firstFrame + 51].width / 2 : jjAnimFrames[jjAnimations[jjAnimSets[ANIM::FONT].firstAnim + 2].firstFrame + 16].width / 2);
particle.yPos = player.cameraY + topMargin + (smallLine * 6) + (bigLine * 5) + (smallScreen ? jjAnimFrames[jjAnimations[jjAnimSets[ANIM::FONT].firstAnim].firstFrame + 51].height / 2 : jjAnimFrames[jjAnimations[jjAnimSets[ANIM::FONT].firstAnim + 2].firstFrame + 16].height / 2);
particle.xSpeed = int(jjRandom() % 9 - 4);
particle.ySpeed = int(jjRandom() % 9 - 4);
particle.star.angularSpeed = int(jjRandom() % 4 + 1);
particle.star.color = int(jjRandom() % 3 + 40);
particle.star.size = int(jjRandom() % 24 + 24);
}
fanfarePlayed = true;
}
} else if ((player.score - startingScore[player.localPlayerID] + timeBonus[player.localPlayerID] - hitPenalty[player.localPlayerID]) * jjLocalPlayerCount > maxScore * 1.3) {
canvas.drawResizedSprite(leftIndent, topMargin + (smallLine * 6) + (bigLine * 5), ANIM::FONT, smallScreen ? 0 : 2, 33, rankStamp, rankStamp, SPRITE::PALSHIFT, 208);
if (!fanfarePlayed && rankStamp == 1) {
jjSamplePriority(SOUND::INTRO_BOEM2);
int doinky = int(jjRandom() % 12 + 12);
for (int i = 0; i < doinky; i++) {
jjPARTICLE@ particle = jjAddParticle(PARTICLE::STAR);
particle.xPos = player.cameraX + leftIndent + (smallScreen ? jjAnimFrames[jjAnimations[jjAnimSets[ANIM::FONT].firstAnim].firstFrame + 33].width / 2 : jjAnimFrames[jjAnimations[jjAnimSets[ANIM::FONT].firstAnim + 2].firstFrame + 33].width / 2);
particle.yPos = player.cameraY + topMargin + (smallLine * 6) + (bigLine * 5) + (smallScreen ? jjAnimFrames[jjAnimations[jjAnimSets[ANIM::FONT].firstAnim].firstFrame + 33].height / 2 : jjAnimFrames[jjAnimations[jjAnimSets[ANIM::FONT].firstAnim + 2].firstFrame + 33].height / 2);
particle.xSpeed = int(jjRandom() % 9 - 4);
particle.ySpeed = int(jjRandom() % 9 - 4);
particle.star.angularSpeed = int(jjRandom() % 4 + 1);
particle.star.color = int(jjRandom() % 3 + 16);
particle.star.size = int(jjRandom() % 16 + 24);
}
fanfarePlayed = true;
}
} else if ((player.score - startingScore[player.localPlayerID] + timeBonus[player.localPlayerID] - hitPenalty[player.localPlayerID]) * jjLocalPlayerCount > maxScore * 1.1) {
canvas.drawResizedSprite(leftIndent, topMargin + (smallLine * 6) + (bigLine * 5), ANIM::FONT, smallScreen ? 0 : 2, 34, rankStamp, rankStamp, SPRITE::PALSHIFT, 216);
} else if ((player.score - startingScore[player.localPlayerID] + timeBonus[player.localPlayerID] - hitPenalty[player.localPlayerID]) * jjLocalPlayerCount > maxScore * 0.9) {
canvas.drawResizedSprite(leftIndent, topMargin + (smallLine * 6) + (bigLine * 5), ANIM::FONT, smallScreen ? 0 : 2, 35, rankStamp, rankStamp, SPRITE::PALSHIFT, 224);
} else if ((player.score - startingScore[player.localPlayerID] + timeBonus[player.localPlayerID] - hitPenalty[player.localPlayerID]) * jjLocalPlayerCount > maxScore * 0.7) {
canvas.drawResizedSprite(leftIndent, topMargin + (smallLine * 6) + (bigLine * 5), ANIM::FONT, smallScreen ? 0 : 2, 36, rankStamp, rankStamp, SPRITE::PALSHIFT, 16);
} else {
canvas.drawResizedSprite(leftIndent, topMargin + (smallLine * 6) + (bigLine * 5), ANIM::FONT, smallScreen ? 0 : 2, 37, rankStamp, rankStamp, SPRITE::PALSHIFT, 8);
if (!fanfarePlayed && rankStamp == 1) {
jjSamplePriority(SOUND::INTRO_BLOW);
fanfarePlayed = true; // well you could say that
}
}
}
}
void rankingInterface(jjPLAYER@ player) {
if (jjDifficulty == 0 && player.lives < 3) player.lives = 3;
if (player.blink == -207) hitPenalty[player.localPlayerID] += 1000;
if (levelOver) {
player.timerStop();
player.invincibility = -15;
player.idle = 0;
player.noFire = true;
jjCharacters[player.charCurr].canRun = false; // block revving
player.keyLeft = player.keyRight = player.keyDown = player.keyUp = player.keyRun = player.keyJump = false;
if ((player.keyFire || player.keySelect || jjKey[1]) && rankLineCD == 0) {
rankLineCD = 60;
rankLine++;
player.keySelect = player.keyFire = false;
}
}
}
void savePost(jjOBJ@ save) {
switch(save.state) {
case STATE::START:
timerMsgCD = 0;
break;
case STATE::ACTION:
if (timerMsgCD == 0) {
if (jjLocalPlayerCount == 1) { // not abusable in coop this way until onLevelReload is improved
storeScoreSeconds = scoreSeconds;
}
jjAlert(formatInt(scoreSeconds / 60) + ":" + formatInt(scoreSeconds % 60, '0', 2));
timerMsgCD = 100;
}
break;
case STATE::DONE:
if (timerMsgCD > 0) { timerMsgCD--; }
break;
}
save.behave(BEHAVIOR::CHECKPOINT);
}
void endLevel(jjPLAYER@ player, bool warpEnd = false, bool exitLeft = false) {
if (player.charCurr != player.charOrig) player.revertMorph();
player.fly = FLIGHT::NONE;
levelOver = true;
exitLeftAnim = exitLeft;
if (scoreSeconds > (bestTime * 3)) timeBonus[player.localPlayerID] = 0;
else if (scoreSeconds > bestTime) {
timeDifference = bestTime * 3 - scoreSeconds; // level is over once any player finishes, so don't need scoreSeconds to be an array
timeBonus[player.localPlayerID] = int(ceil(maxScore * (timeDifference / (bestTime * 2)) / 100) * 100);
} else timeBonus[player.localPlayerID] = maxScore;
if (!jinglePlayed) {
jjMusicStop();
switch(player.charCurr) {
case CHAR::JAZZ:
jjSamplePriority(SOUND::ENDTUNEJAZZ_TUNE);
break;
case CHAR::SPAZ:
jjSamplePriority(SOUND::ENDTUNESPAZ_TUNE);
break;
case CHAR::LORI:
jjSamplePriority(SOUND::ENDTUNELORI_CAKE);
break;
}
jinglePlayed = true;
}
warpAnim = warpEnd;
}
void initFade() {
jjANIMSET@ fadeAnim = jjAnimSets[ANIM::CUSTOM[255]];
fadeAnim.allocate(array<uint>={1});
fadeAnim.load(
jjPIXELMAP("STVcartoonfade_fade.png"),
frameWidth: 600,
frameHeight: 600,
frameSpacingX: 0,
frameSpacingY: 0,
startY: 0,
firstAnimToOverwrite: jjAnimSets[ANIM::CUSTOM[255]]
);
}
void updateFade() {
if (isFading) {
fadeScale += FADE_SCALE_STEP;
if (fadeScale >= 4) {
isFading = false;
}
}
if (!isFading && fadeScale >= 4 && gtfoAnim < 154) {
if (gtfoAnim == 1) {
if (warpAnim) jjSamplePriority(SOUND::COMMON_TELPORT1);
else jjSamplePriority(SOUND::COMMON_REVUP);
}
if (gtfoAnim == 69) jjSamplePriority(SOUND::AMMO_BULFL3); // nice
gtfoAnim++;
}
if (gtfoAnim == 49 && warpAnim) jjNxt(false, true); // you'll need to manually make the player warp in at the start of next level but this is more reliable than the original effect
if (gtfoAnim == 154 && !warpAnim) jjNxt(false, true);
}
void drawFade(jjPLAYER@ player, jjCANVAS@ canvas) {
int adjustedXPos = int(player.xPos) - int(player.cameraX);
int adjustedYPos = int(player.yPos) - int(player.cameraY);
canvas.drawResizedSprite(
adjustedXPos, adjustedYPos,
ANIM::CUSTOM[255], 0, 0,
fadeScale, fadeScale,
SPRITE::ALPHAMAP, 1
);
if (isFading) {
switch(player.charOrig) {
case CHAR::JAZZ:
canvas.drawSprite(adjustedXPos, adjustedYPos, ANIM::JAZZ, RABBIT::STAND, player.curFrame, exitLeftAnim ? -1 : 1);
break;
case CHAR::SPAZ:
canvas.drawSprite(adjustedXPos, adjustedYPos, ANIM::SPAZ, RABBIT::STAND, player.curFrame, exitLeftAnim ? -1 : 1);
break;
case CHAR::LORI:
canvas.drawSprite(adjustedXPos, adjustedYPos, ANIM::LORI, RABBIT::STAND, player.curFrame, exitLeftAnim ? -1 : 1);
break;
}
}
if (!isFading && fadeScale >= 4 && gtfoAnim < 154 && !warpAnim) {
switch(player.charOrig) {
case CHAR::JAZZ:
canvas.drawSprite(adjustedXPos, adjustedYPos, ANIM::JAZZ, RABBIT::ENDOFLEVEL, uint8(gtfoAnim / 7), exitLeftAnim ? -1 : 1);
break;
case CHAR::SPAZ:
canvas.drawSprite(adjustedXPos, adjustedYPos, ANIM::SPAZ, RABBIT::ENDOFLEVEL, uint8(gtfoAnim / 7), exitLeftAnim ? -1 : 1);
break;
case CHAR::LORI:
canvas.drawSprite(adjustedXPos, adjustedYPos, ANIM::LORI, RABBIT::ENDOFLEVEL, uint8(gtfoAnim / 7), exitLeftAnim ? -1 : 1);
break;
}
}
if (!isFading && fadeScale >= 4 && gtfoAnim < 49 && warpAnim) {
switch(player.charOrig) {
case CHAR::JAZZ:
canvas.drawSprite(adjustedXPos, adjustedYPos, ANIM::JAZZ, RABBIT::TELEPORT, uint8(gtfoAnim / 7), exitLeftAnim ? -1 : 1);
break;
case CHAR::SPAZ:
canvas.drawSprite(adjustedXPos, adjustedYPos, ANIM::SPAZ, RABBIT::TELEPORT, uint8(gtfoAnim / 7), exitLeftAnim ? -1 : 1);
break;
case CHAR::LORI:
canvas.drawSprite(adjustedXPos, adjustedYPos, ANIM::LORI, RABBIT::TELEPORT, uint8(gtfoAnim / 7), exitLeftAnim ? -1 : 1);
break;
}
}
}
void fade() {
isFading = true;
}
void infiniteLives(jjPLAYER@ player, jjCANVAS@ canvas) {
int charHead;
switch(player.charCurr) {
case CHAR::BIRD2: charHead = 0; break;
case CHAR::BIRD: charHead = 1; break;
case CHAR::FROG: charHead = 2; break;
case CHAR::JAZZ: charHead = 3; break;
case CHAR::LORI: charHead = 4; break;
case CHAR::SPAZ: charHead = 5; break;
}
canvas.drawSprite(0, int(jjSubscreenHeight), ANIM::FACES, charHead, (jjGameTicks/7) % 36);
if (smallScreen) canvas.drawString(32, int(jjSubscreenHeight - 9), "x^");
else canvas.drawString(32, int(jjSubscreenHeight - 14), "x^", STRING::MEDIUM);
}
void oneUpsIntoBlueGems() {
for (int i = jjObjectCount; --i > 0;) {
jjOBJ@ obj = jjObjects[i];
if (obj.eventID == 80 && obj.isActive) {
jjOBJ@ lifegem = jjObjects[jjAddObject(OBJECT::BLUEGEM, obj.xPos, obj.yPos)];
lifegem.deactivates = false;
obj.delete();
}
}
}
void setTimer() {
for (int i = 0; i < (jjLocalPlayerCount + 1); i++) {
if (jjDifficulty == 0 && easyTimer > 0) jjLocalPlayers[i].timerStart(easyTimer, false);
if (jjDifficulty == 1 && normalTimer > 0) jjLocalPlayers[i].timerStart(normalTimer, false);
if (jjDifficulty == 2 && hardTimer > 0) jjLocalPlayers[i].timerStart(hardTimer, false);
if (jjDifficulty == 3 && turboTimer > 0) jjLocalPlayers[i].timerStart(turboTimer, false);
jjLocalPlayers[i].timerPersists = true;
}
jjObjectPresets[OBJECT::FREEZER].points = 500;
jjObjectPresets[OBJECT::FREEZER].scriptedCollisions = true;
jjObjectPresets[OBJECT::FREEZER].behavior = timerExtend();
}
void onPlayerTimerEnd(jjPLAYER@ player) {
player.kill();
switch (jjDifficulty) {
case 0: player.timerStart(easyTimer + 140, false); break;
case 1: player.timerStart(normalTimer + 140, false); break;
case 2: player.timerStart(hardTimer + 140, false); break;
case 3: player.timerStart(turboTimer + 140, false); break;
}
}
class timerExtend : jjBEHAVIORINTERFACE {
int addedTime;
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::PICKUP);
switch (jjDifficulty) {
case 0: addedTime = 8; break;
case 1: addedTime = 4; break;
case 2: addedTime = 2; break;
case 3: addedTime = 1; break;
}
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@, jjPLAYER@ player, int) {
player.frozen = 0;
player.timerTime += 4200 * addedTime;
jjPARTICLE@ particle = jjAddParticle(PARTICLE::STRING);
if (particle !is null) {
particle.xPos = obj.xPos;
particle.yPos = obj.yPos;
particle.xSpeed = (-32768 - int(jjRandom() & 0x3FFF)) / -65536.f; // positive
particle.ySpeed = (-65536 - int(jjRandom() & 0x7FFF)) / 65536.f; // negative
particle.string.text = "+" + formatInt(addedTime) + "min!";
}
obj.behavior = BEHAVIOR::EXPLOSION2;
obj.scriptedCollisions = false;
obj.frameID = 0;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PICKUP1);
return true;
}
}
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.