Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Holiday Hare '17 | ShadowGPW | Single player | 8.8 |
#include "MLLE-Include-1.6.asc" ///@MLLE-Generated
const bool MLLESetupSuccessful = MLLE::Setup();
#pragma require "HH17_Level06-MLLE-Data-2.j2l"
#pragma require "HH17_Level06-MLLE-Data-1.j2l"
#pragma require "HH17_Level06.j2l"
#include "HH17Enemies.asc"
#pragma require "Jazz1Nippius.j2t"
#pragma require "HolidaiusN.j2t"
#pragma require "CrysilisV3.j2t"
#pragma require "BioWinter.j2t"
#pragma require "HH17_lowind.wav"
#pragma require "HH17_caveamb.wav"
#pragma require "HH17_Glass1.wav"
#pragma require "HH17_Glass2.wav"
#pragma require "HH17_Glass3.wav"
#pragma require "HH17_Glass4.wav"
#pragma require "HH17_Null.wav"
#include "Jazz1Enemies v03.asc"
#pragma require "SExmas.j2a"
#pragma require "HH17_Icicle.j2a"
#include "kangaroo.asc"
#pragma require "kangaroo.asc"
#pragma offer "Boss.s3m"
#pragma offer "ckbattle.mo3"
#pragma offer "Xmas 1.s3m"
bool blizzard = true;
uint R = 210, G = 200, B = 220;
jjPAL pal;
bool refresh = false;
int bossActivateTime = 0;
int elapsed = 0;
enum queenPhases {None, PhaseOne, Transition, PhaseTwo, Dying, Complete};
uint currPhase = None;
int transitionTime = 0;
enum queenStates {Fall, Move, Stand, Scream, Stomp, Float};
uint currState = Fall;
int rand = 3;
int randcar = 20;
bool cutscene = false;
bool cutsceneComplete = false;
int cutsceneTime = 0;
class vector2i {
int x, y;
}
array<vector2i> oneWays;
void onLevelLoad() {
Jazz1::MakeEnemy(OBJECT::TUBETURTLE, Jazz1::Enemies::Nippius_SkatePen);
Kangaroo::MakeEventJoey(OBJECT::FATCHICK, 0, 5, 4, 16, 14, 256);
jjObjectPresets[OBJECT::FATCHICK].behavior = function(obj) {
obj.behavior = JoeyWithTrail(64, 5);
obj.behave();
};
HH17::replaceAllEnemies();
jjTexturedBGTexture = TEXTURE::DIAMONDUSBETA;
jjUseLayer8Speeds = true;
jjObjectPresets[OBJECT::STEADYLIGHT].behavior = SnowEffect();
jjObjectPresets[OBJECT::AMBIENTSOUND].behavior = AmbientSound();
jjObjectPresets[OBJECT::AMBIENTSOUND].deactivates = false;
jjObjectPresets[OBJECT::GREENSPRING].deactivates = false;
jjObjectPresets[OBJECT::BLUESPRING].deactivates = false;
jjObjectPresets[OBJECT::AIRBOARD].deactivates = false;
jjObjectPresets[OBJECT::TUBETURTLE].energy = 1;
jjObjectPresets[OBJECT::TUBETURTLE].points = 200;
jjObjectPresets[OBJECT::FISH].behavior = FrozenFish();
jjObjectPresets[OBJECT::QUEEN].behavior = IceQueen();
jjObjectPresets[OBJECT::LIZARD].behavior = IceQueenPhaseTwo();
jjObjectPresets[OBJECT::LIZARD].energy = 100;
jjObjectPresets[OBJECT::LIZARD].age = 150;
jjObjectPresets[OBJECT::LIZARD].points = 10000;
jjObjectPresets[OBJECT::LIZARD].scriptedCollisions = true;
jjObjectPresets[OBJECT::LIZARD].playerHandling = HANDLING::SPECIAL;
jjObjectPresets[OBJECT::LIZARD].bulletHandling = HANDLING::DETECTBULLET;
jjObjectPresets[OBJECT::LIZARD].isBlastable = false;
jjObjectPresets[OBJECT::LIZARD].isTarget = true;
jjObjectPresets[OBJECT::BUBBA].behavior = Bubba();
jjObjectPresets[OBJECT::BUBBA].energy = 20;
jjObjectPresets[OBJECT::TUFBOSS].behavior = TuffBoss();
jjObjectPresets[OBJECT::TUFBOSS].energy = 30;
jjObjectPresets[OBJECT::BUTTERFLY].behavior = HandleMovingPlatforms();
jjObjectPresets[OBJECT::BUTTERFLY].playerHandling = HANDLING::PARTICLE;
jjObjectPresets[OBJECT::BUTTERFLY].bulletHandling = HANDLING::IGNOREBULLET;
jjObjectPresets[OBJECT::BUTTERFLY].isBlastable =
jjObjectPresets[OBJECT::BUTTERFLY].triggersTNT =
jjObjectPresets[OBJECT::BUTTERFLY].isTarget = false;
jjObjectPresets[OBJECT::PINKPLATFORM].behavior = MovingPlatform();
jjObjectPresets[OBJECT::STRAWBERRY].behavior = PurpleJazz();
jjObjectPresets[OBJECT::STRAWBERRY].playerHandling = HANDLING::PARTICLE;
jjObjectPresets[OBJECT::STRAWBERRY].bulletHandling = HANDLING::IGNOREBULLET;
jjSampleLoad(SOUND::WIND_WIND2A, "HH17_lowind.wav");
jjSampleLoad(SOUND::SCIENCE_PLOPKAOS, "HH17_caveamb.wav");
jjSampleLoad(SOUND::COMMON_DAMPED1, "HH17_Glass1.wav");
jjSampleLoad(SOUND::COMMON_COLLAPS, "HH17_Null.wav");
jjSampleLoad(SOUND::SKELETON_BONE1, "HH17_Glass2.wav");
jjSampleLoad(SOUND::SKELETON_BONE2, "HH17_Glass3.wav");
jjSampleLoad(SOUND::SKELETON_BONE3, "HH17_Glass4.wav");
jjObjectPresets[OBJECT::COLLAPSESCENERY].behavior = CollapsingIce;
Imitation(OBJECT::TACO, OBJECT::MILK);
uint src = jjAnimSets[ANIM::CUSTOM[255]].load(0, "SExmas.j2a");
uint dest = jjAnimSets[ANIM::PICKUPS];
for (int i = 0; i < 95; i++) {
const jjANIMATION@ anim = jjAnimations[src + i];
if (anim.frameCount != 0)
jjAnimations[dest + i] = anim;
}
jjAnimSets[ANIM::CUSTOM[2]].load(0, "HH17_Icicle.j2a");
jjAnimSets[ANIM::BRIDGE].load(1, "SExmas.j2a");
jjWeapons[WEAPON::TNT].comesFromGunCrates = jjWeapons[WEAPON::GUN8].comesFromGunCrates = jjWeapons[WEAPON::GUN9].comesFromGunCrates = true;
jjANIMATION@ animBrick = jjAnimations[jjAnimSets[ANIM::QUEEN] + 4];
for (uint j = 0; j < animBrick.frameCount; j++) {
jjANIMFRAME@ frame = jjAnimFrames[animBrick + j];
jjPIXELMAP sprite(frame);
for (uint x = 0; x < sprite.width; ++x) {
for (uint y = 0; y < sprite.height; ++y) {
if (sprite[x,y] != 254) sprite[x,y] = 0;
}
}
sprite.save(frame);
}
jjAnimSets[ANIM::CUSTOM[0]].load(2, "SExmas.j2a");
jjObjectPresets[OBJECT::ONEUPCRATE].behavior = GiftBox();
jjObjectPresets[OBJECT::ONEUPCRATE].determineCurAnim(ANIM::CUSTOM[0], 0);
jjObjectPresets[OBJECT::BIGBOX].behavior = LayerFiveBox();
jjAnimSets[ANIM::SPIKEPLAT].load(4, "SExmas.j2a");
jjObjectPresets[OBJECT::SPIKEPLATFORM].killAnim = jjObjectPresets[OBJECT::SPIKEPLATFORM].determineCurAnim(ANIM::SPIKEPLAT, 0) + 1;
}
void onLevelBegin() {
for (int i = 0; i < jjLocalPlayerCount; i++) {
jjLocalPlayers[i].activateBoss(true);
jjLocalPlayers[i].bossActivated = true;
bossActivateTime = 0;
}
jjANIMATION@ animKangaroo = jjAnimations[jjAnimSets[ANIM::CUSTOM[1]] + 0];
for (uint j = 0; j < animKangaroo.frameCount; j++) {
jjANIMFRAME@ frame = jjAnimFrames[animKangaroo + j];
jjPIXELMAP sprite(frame);
for (uint x = 0; x < sprite.width; ++x) {
for (uint y = 0; y < sprite.height; ++y) {
if (sprite[x,y] >= 40 && sprite[x,y] <= 47) sprite[x,y] -= 2;
if (sprite[x,y] >= 48 && sprite[x,y] <= 55) sprite[x,y] += 16;
}
}
sprite.save(frame);
}
for (uint i = 0; i < 3; i++) {
jjANIMATION@ animDragon = jjAnimations[jjAnimSets[ANIM::DRAGON] + i];
for (uint j = 0; j < animDragon.frameCount; j++) {
jjANIMFRAME@ frame = jjAnimFrames[animDragon + j];
jjPIXELMAP sprite(frame);
for (uint x = 0; x < sprite.width; ++x) {
for (uint y = 0; y < sprite.height; ++y) {
if (sprite[x,y] >= 72 && sprite[x,y] <= 77) sprite[x,y] += 9;
if (sprite[x,y] == 78) sprite[x,y] = 86;
if (sprite[x,y] == 79) sprite[x,y] = 87;
}
}
sprite.save(frame);
}
}
if (jjGameConnection != GAME::LOCAL) jjAlert("|Warning: This level is not designed to be played online!");
}
void onLevelReload() {
MLLE::Palette.apply();
HH17::processEnemyColors();
refresh = true;
currState = Fall;
for (int i = 0; i < jjLocalPlayerCount; i++) {
jjLocalPlayers[i].activateBoss(true);
jjLocalPlayers[i].bossActivated = true;
bossActivateTime = 0;
}
array<jjLAYER@> layers = jjLayerOrderGet();
for (int l = 0; l < 20; l++) {
layers[l].hasTiles = true;
}
if (currPhase < Complete) {
currPhase = None;
jjTexturedBGTexture = TEXTURE::DIAMONDUSBETA;
jjTexturedBGStyle = TEXTURE::WARPHORIZON;
jjSetFadeColors(118,108,138);
jjLayerXAutoSpeed[8] = 0.25;
jjMusicLoad("lemonade-snowmelt.mo3", false);
} else {
jjMusicLoad("Xmas 1.s3m", false);
jjPalette.gradient(0,125,255, 255,255,255);
jjPalette.apply();
}
}
class GiftBox : jjBEHAVIORINTERFACE {
void destroy(jjOBJ@ obj) {
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_WOOD1);
{
int id = jjAddObject(OBJECT::EXPLOSION, obj.xPos, obj.yPos);
if (id != 0) {
jjOBJ@ other = jjObjects[id];
other.determineCurAnim(ANIM::PICKUPS, 4);
}
}
for (int i = jjRandom() & 7 | 8; i-- != 0;) {
int id = jjAddObject(OBJECT::SHARD, obj.xPos, obj.yPos);
if (id != 0) {
jjOBJ@ other = jjObjects[id];
other.determineCurAnim(ANIM::PICKUPS, 93 + (jjRandom() & 1));
}
}
obj.yPos -= 8.f;
for (int i = obj.var[1]; i-- != 0;) {
int id = jjAddObject(obj.var[0], obj.xPos, obj.yPos);
if (id != 0) {
jjOBJ@ other = jjObjects[id];
if (other.playerHandling == HANDLING::PICKUP) {
int angle = (jjRandom() & 255) + 128;
other.xSpeed = jjCos(angle) * 5.f;
other.ySpeed = jjSin(angle) * -3.f;
} else if (other.playerHandling == HANDLING::SPECIAL) {
other.deactivates = false;
}
}
}
obj.clearPlatform();
obj.delete();
}
void onBehave(jjOBJ@ obj) override {
switch (obj.state) {
case STATE::START:
{
uint16 x = int(obj.xOrg) >>> 5;
uint16 y = int(obj.yOrg) >>> 5;
obj.var[0] = jjParameterGet(x, y, 0, 8);
obj.var[1] = jjParameterGet(x, y, 8, 4);
obj.curAnim += jjParameterGet(x, y, 12, 2);
obj.determineCurFrame();
obj.bulletHandling = HANDLING::DESTROYBULLET;
obj.scriptedCollisions = true;
}
break;
case STATE::FALL:
obj.var[2] = 1;
break;
case STATE::FREEZE:
case STATE::SLEEP:
if (obj.var[2] != 0) {
destroy(obj);
return;
}
}
obj.behave(BEHAVIOR::MONITOR);
}
bool onObjectHit(jjOBJ@, jjOBJ@, jjPLAYER@, int) {
return true;
}
bool onIsSolid(jjOBJ@) {
return true;
}
}
const array<SOUND::Sample> CollapsingIceSounds = {
SOUND::SKELETON_BONE1,
SOUND::SKELETON_BONE2,
SOUND::SKELETON_BONE3
};
void CollapsingIce(jjOBJ@ obj) {
if (obj.state == STATE::EXTRA) {
jjSample(obj.xPos, obj.yPos, CollapsingIceSounds[jjRandom()%3]);
int SpikeX = int(obj.xPos) >>> 5;
int SpikeY = (int(obj.yPos) >>> 5) - 1;
if (jjEventGet(SpikeX, SpikeY) == AREA::HURT) {
jjTileSet(4, SpikeX, SpikeY, 160);
jjAddParticleTileExplosion(SpikeX, SpikeY, 515, true);
jjSample(obj.xPos, obj.yPos - 32, CollapsingIceSounds[jjRandom()%3]);
}
}
obj.behave(BEHAVIOR::DESTRUCTSCENERY);
}
bool inView(const jjOBJ@ obj) {
for (int i = 0; i < jjLocalPlayerCount; i++) {
const jjPLAYER@ player = jjLocalPlayers[i];
if (obj.xPos > player.cameraX - 64 && obj.yPos > player.cameraY - 64 && obj.xPos < player.cameraX + jjSubscreenWidth + 64 && obj.yPos < player.cameraY + jjSubscreenHeight + 64)
return true;
}
return false;
}
class SnowEffect : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::STEADYLIGHT);
obj.deactivates = false;
obj.light = blizzard && jjLocalPlayerCount == 1 && (jjLocalPlayers[0].lighting > 5 && jjLocalPlayers[0].lighting < 101)? 127:-127;
obj.xPos = jjLocalPlayers[0].cameraX + 400;
obj.yPos = jjLocalPlayers[0].cameraY + 300;
}
}
class AmbientSound : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ sound) {
sound.deactivates = false;
sound.behave((jjLowDetail && jjGameTicks >= 2) || currPhase >= PhaseTwo? BEHAVIOR::INACTIVE : BEHAVIOR::AMBIENTSOUND, false);
sound.deactivates = false;
if (blizzard) {
if (sound.yOrg > 4480) loopSound(sound);
else sound.yPos = jjLocalPlayers[0].yPos + 160;
} else if (!blizzard) {
if (sound.yOrg < 4480) loopSound(sound);
else sound.yPos = jjLocalPlayers[0].yPos + 160;
}
}
}
void loopSound(jjOBJ@ sound) {
sound.xPos = jjLocalPlayers[0].xPos;
sound.yPos = jjLocalPlayers[0].yPos;
}
class Imitation : jjBEHAVIORINTERFACE {
private uint8 eventID;
private jjBEHAVIOR behavior;
Imitation(uint8 realEventID, uint8 fakeEventID) {
jjOBJ@ obj = jjObjectPresets[realEventID];
eventID = obj.eventID;
behavior = obj.behavior;
obj.eventID = fakeEventID;
obj.behavior = this;
}
void onBehave(jjOBJ@ obj) override {
if (obj.state == STATE::DEACTIVATE)
obj.eventID = eventID;
obj.behave(behavior);
}
}
class JoeyWithTrail : jjBEHAVIORINTERFACE {
private int trailLength;
private array<float> xPrev;
private array<float> yPrev;
private int index = 0;
private uint8 color;
JoeyWithTrail(int trailLength, uint8 color) {
this.trailLength = trailLength;
for (int i = 0; i < trailLength; i++) {
xPrev.insertLast(-1e3f);
yPrev.insertLast(-1e3f);
}
this.color = color;
}
void onBehave(jjOBJ@ obj) override {
float xPos = obj.xPos;
float yPos = obj.yPos;
obj.behave(Kangaroo::Joey, false);
for (int i = 0; i < trailLength; i++) {
int j = (index + i) % trailLength;
if (!closeTo(xPrev[j], obj.xPos) || !closeTo(yPrev[j], obj.yPos)) {
float scale = 0.5f * i / trailLength;
jjDrawResizedSprite(xPrev[j], yPrev[j], ANIM::AMMO, 10, 0, scale, scale, SPRITE::SINGLECOLOR, color);
}
}
obj.draw();
float xInc = (obj.xPos - xPos) / 4;
float yInc = (obj.yPos - yPos) / 4;
for (int i = 0; i < 4; i++) {
xPrev[index] = xPos += xInc;
yPrev[index] = yPos += yInc;
index = (index + 1) % trailLength;
}
}
}
bool givePlayerPointsForObject(jjPLAYER@ player, jjOBJ@ obj) { //This will probably be made a jjOBJ method as part of the real JJ2+ API eventually, because it shows up all the time in the native code, but that hasn't happened yet, so here you go. Increases the player's jjPLAYER::score to match the object's jjOBJ::points, and creates a string particle with that number which flies up to the top left corner of the screen.
if (player is null)
return false;
if (obj.points != 0 && (jjGameMode == GAME::SP || jjGameMode == GAME::COOP)) {
player.score += obj.points;
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;
particle.ySpeed = (-65536 - int(jjRandom() & 0x7FFF)) / 65536.f;
particle.string.text = formatInt(obj.points);
}
obj.points = 0; //Ensures that JJ2 won't end up increasing the player's score TWICE, since a call to (the native version of) this function is actually part of the standard pickup-handling code and would otherwise therefore get you in trouble with the FiveUp onObjectHit code.
return true;
}
return false;
}
void onPlayer(jjPLAYER@ play) {
for (uint i = 0; i < oneWays.length(); i++) {
jjEventSet(oneWays[i].x, oneWays[i].y, AREA::ONEWAY);
}
oneWays.resize(0);
int px = int(play.xPos), py = int(play.yPos);
bool masked;
for (int i = -11 + int(play.ySpeed); i <= 14; i++) {
if (masked = jjMaskedHLine(px - 14, 28, py + i))
break;
}
if (!masked) {
for (int i = 8; i <= 16; i += 8) {
for (int j = 12; j <= 20; j += 8) {
int x = (px + play.direction * j) >>> 5, y = (py + i) >>> 5;
if (x >= 0 && y >= 0 && x < jjLayerWidth[4] && y < jjLayerHeight[4] && jjEventGet(x, y) == AREA::ONEWAY) {
vector2i point;
jjEventSet(point.x = x, point.y = y, 0);
oneWays.insertLast(point);
}
}
}
}
if (currPhase != PhaseTwo) play.boss = 0;
if (play.bossActivated) bossActivateTime++;
if (bossActivateTime >= 35 && currPhase != PhaseTwo) play.bossActivated = false;
else play.bossActivated = true;
if (currPhase <= PhaseOne) {
play.lighting = blizzard && jjLocalPlayerCount == 1? (50 + int(jjSin(jjGameTicks)*5)) : jjLocalPlayerCount > 1? 100 : 60;
} else {
if (currPhase == Transition) {
transitionTime++;
if (jjGameTicks % 14 == 0 && transitionTime >= 70) {
if (play.lighting > 0) play.lighting = play.lighting - 1;
}
if (transitionTime == 1 && jjDifficulty <= 1) {
jjOBJ@ carrot = jjObjects[jjAddObject(OBJECT::FULLENERGY, 578*32, 16*32, 0, CREATOR::LEVEL)];
carrot.state = STATE::FLOATFALL;
}
if (transitionTime == 70) {
play.showText("@@@@@@@@@You feel yourself being swallowed@@by the raging blizzard...", STRING::MEDIUM);
}
if (transitionTime >= 490) {
currPhase = PhaseTwo;
jjMusicLoad("ckbattle.mo3");
jjMusicPlay();
blizzard = true;
play.warpToID(250, true);
play.cameraFreeze(642.5*32, 89*32, true, true);
}
} else {
if (currPhase == PhaseTwo) {
play.lighting = 30;
transitionTime = 0;
}
}
if (currPhase == Dying) {
transitionTime++;
if (play.lighting > 0) play.lighting = play.lighting - 1;
if (transitionTime >= 350) {
play.showText("@@@@@@@@@The blizzard subsided.", STRING::MEDIUM);
currPhase = Complete;
jjMusicLoad("Xmas 1.s3m", false);
jjMusicPlay();
jjTexturedBGTexture = TEXTURE::DIAMONDUSBETA;
jjTexturedBGStyle = TEXTURE::WARPHORIZON;
jjSetFadeColors(118,108,138);
jjLayerXAutoSpeed[8] = 0.25;
play.warpToID(251, true);
jjPalette.gradient(0,125,255, 255,255,255);
jjPalette.apply();
jjTriggers[28] = true;
}
}
if (currPhase == Complete) {
if (blizzard) play.lighting = 110;
else play.lighting = 60;
}
}
play.lightType = LIGHT::NONE;
jjEnforceLighting = currPhase == Transition || currPhase == Dying? LIGHT::COMPLETE : LIGHT::OPTIONAL;
if (currPhase != Transition) {
if (blizzard) {
if (R < 210) R+=2;
else if (R > 210) R-=2;
if (G < 200) G+=2;
else if (G > 200) G-=2;
if (B < 220) B+=2;
else if (B > 220) B-=2;
} else {
if (R < 20) R+=2;
else if (R > 20) R-=2;
if (G < 10) G+=2;
else if (G > 10) G-=2;
if (B < 60) B+=2;
else if (B > 60) B-=2;
}
} else {
if (R < 250) R++;
else if (R > 250) R--;
if (G < 250) G++;
else if (G > 250) G--;
if (B < 250) B++;
else if (B > 250) B--;
}
if (currPhase == Complete) {
play.cameraUnfreeze(true);
}
jjSetDarknessColor(jjPALCOLOR(R,G,B));
if (blizzard && jjLocalPlayerCount == 1 && currPhase != Complete) jjIsSnowing = true;
else jjIsSnowing = false;
if (refresh) {
play.cameraFreeze(play.xOrg, play.yOrg, true, true);
play.xPos = 6*32;
play.yPos = 145*32;
elapsed++;
if (elapsed == 2) {
play.cameraUnfreeze();
play.xPos = int(play.xOrg + 16);
play.yPos = play.yOrg;
refresh = false;
elapsed = 0;
}
}
if (cutscene) {
cutsceneTime++;
play.keyLeft = play.keyRight = play.keyUp = play.keyDown = play.keyFire = play.keyJump = play.keyRun = false;
play.idle = 0;
play.xSpeed = 0;
switch (cutsceneTime) {
case 5:
jjAlert("|||||Thank you for rescuing me!");
break;
case 215:
jjAlert("|||||Slaying the Ice Queen seems to have ended this dreadful blizzard.");
break;
case 425:
jjAlert("|||||I'm so glad you got here when you did, I probably would've frozen to death!");
break;
case 635:
jjAlert("|||||You're probably looking for the stolen presents, right?");
break;
case 845:
jjAlert("|||||Well, I hate to be the bearer of bad news, but they're not here.");
break;
case 1005:
jjAlert("|||||I overheard that the Ice Queen gave them to her pet dragon to protect.");
break;
case 1265:
jjAlert("|||||The dragon's lair is about 60 miles to the north of here, in the icy caverns");
jjAlert("|||||beneath this high mountain range.");
break;
case 1475:
jjAlert("|||||So... yeah. You'd better pay him a visit if you want them back...");
break;
case 1685:
jjAlert("|||||I'd better go now, my tea's probably stone cold!");
break;
case 1895:
jjAlert("|||||Oh, by the way, you can have this. I managed to smuggle it into my cell.");
jjAlert("|||||Merry Christmas! Now I'd better skiddadle...");
break;
case 2245:
cutscene = false;
cutsceneComplete = true;
break;
default: break;
}
}
}
void onMain() {
for (int i = 0; i < 1024; i++) {
jjPARTICLE@ particle = jjParticles[i];
if (particle.type == PARTICLE::SNOW) {
if (currPhase <= PhaseOne) {
if (particle.xSpeed < -1) particle.xSpeed = -8 + (jjSin(jjGameTicks)*4);
else particle.xSpeed = -1;
particle.ySpeed = 2 - jjSin(jjGameTicks);
} else {
particle.xSpeed = currPhase == Transition? -16 : -8;
particle.ySpeed = 2;
}
}
}
for (int i = 0; i < jjObjectCount; i++) {
jjOBJ@ obj = jjObjects[i];
if (obj.behavior == BEHAVIOR::BOUNCEONCE && obj.xSpeed == 0 && obj.ySpeed > 0) {
QueenBoulder temp;
jjOBJ@ boulder = jjObjects[jjAddObject(OBJECT::ROTATINGROCK, obj.xPos < 583*32? int(obj.xPos - (jjRandom()%150)) : 583*32, int(obj.yPos - 300), obj.objectID, CREATOR::OBJECT, jjVOIDFUNCOBJ(temp.onBehave))];
boulder.state = STATE::FLY;
boulder.ySpeed = 4;
boulder.xSpeed = 4;
obj.delete();
}
if (obj.eventID == OBJECT::TUBETURTLE) {
obj.xSpeed = 3;
}
if (obj.eventID == OBJECT::TUFTURT) {
if (obj.xOrg > 189*32 && obj.xOrg < 205*32) {
obj.yPos = obj.yOrg;
if ((obj.xPos > obj.xOrg + 80) || (obj.xPos < obj.xOrg - 80)) {
obj.direction *= -1;
}
}
}
}
jjPlayers[31].furSet(88, 32, 16, 16);
HH17::handleEnemyProjectiles();
if (jjGameConnection != GAME::LOCAL) jjTriggers[28] = true;
array<jjLAYER@> layers = jjLayerOrderGet();
if (currPhase == PhaseTwo) {
for (int l = 0; l < 20; l++) {
layers[l].hasTiles = false;
}
jjTexturedBGTexture = TEXTURE::XARGON;
jjSetFadeColors(200,225,255);
jjTexturedBGStyle = TEXTURE::TUNNEL;
jjLayerXAutoSpeed[8] = 1;
} else if (currPhase == Complete) {
for (int l = 0; l < 20; l++) {
layers[l].hasTiles = true;
}
}
if (currPhase >= Transition && currPhase < Complete) jjTriggers[30] = true;
else jjTriggers[30] = false;
if (jjLocalPlayerCount < 2) {
if (currPhase >= PhaseOne && currPhase < Complete) jjTriggers[31] = true;
else jjTriggers[31] = false;
}
}
class FrozenFish : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::FISH, false);
jjDrawSprite(obj.xPos, obj.yPos, ANIM::FISH, 1, 0, obj.direction, SPRITE::FROZEN, 5, 5, 5);
}
}
class LayerFiveBox : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BIGOBJECT, false);
jjDrawSpriteFromCurFrame(obj.xPos, int(obj.yPos + 2), obj.curFrame, obj.direction, obj.freeze == 0? SPRITE::NORMAL : SPRITE::FROZEN, 5, 5, 5);
}
}
class IceQueen : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::QUEEN);
switch (jjDifficulty) {
case 0: obj.var[4] = 34; break;
case 1: obj.var[4] = 24; break;
case 2: obj.var[4] = 24; break;
case 3: obj.var[4] = 14; break;
}
if (obj.state == STATE::ATTACK) {
int playerID = obj.findNearestPlayer(50000);
if (playerID > -1) {
if (jjPlayers[playerID].ySpeed > -1) jjPlayers[playerID].xSpeed -= 1;
} else {
if (jjGameTicks % obj.var[4] == 0) {
Icicle temp;
jjOBJ@ icicle = jjObjects[jjAddObject(OBJECT::BLASTERBULLET, int(obj.xPos + 320), int((obj.yPos + 16) - (jjRandom()%16 * 5)), obj.objectID, CREATOR::OBJECT, jjVOIDFUNCOBJ(temp.onBehave))];
icicle.xSpeed = -8;
icicle.direction = -1;
icicle.counterEnd = 200;
icicle.state = STATE::FLY;
icicle.playerHandling = HANDLING::ENEMYBULLET;
icicle.lightType = LIGHT::NONE;
}
}
for (int i = 0; i < jjObjectCount; i++) {
if (jjObjects[i].eventID == OBJECT::ROTATINGROCK) {
jjObjects[i].state = STATE::FLY;
jjObjects[i].xSpeed -= 1;
}
}
}
if (obj.yPos > 34*32) {
obj.particlePixelExplosion(2);
obj.delete();
if (jjLocalPlayerCount < 2) {
jjMusicStop();
for (int i = 0; i < jjLocalPlayerCount; i++) {
givePlayerPointsForObject(jjLocalPlayers[i], obj);
currPhase = Transition;
}
} else {
currPhase = Complete;
jjMusicLoad("Xmas 1.s3m", false);
jjPalette.gradient(0,125,255, 255,255,255);
jjPalette.apply();
}
}
if (currPhase == Complete || jjGameConnection != GAME::LOCAL) obj.delete();
}
}
class IceQueenPhaseTwo : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.determineCurAnim(ANIM::QUEEN, obj.var[0]);
obj.determineCurFrame();
obj.draw();
if (currState != Fall && obj.freeze == 0) obj.special++;
if (currState != Move) {
if (jjGameTicks % 7 == 0 && obj.freeze == 0) obj.frameID++;
} else {
if (jjGameTicks % 3 == 0 && obj.freeze == 0) obj.frameID--;
}
rand = obj.energy < 50? 4:3;
switch (jjDifficulty) {
case 0: randcar = 10; break;
case 1: randcar = 25; break;
case 2: randcar = 100; break;
default: randcar = 100; break;
}
switch (currState) {
case Fall:
obj.var[0] = 5;
facePlayer(obj);
if (!jjMaskedHLine(int(obj.xPos - 12) , 24, int(obj.yPos + 24))) {
obj.yPos += 2;
} else {
jjSample(jjLocalPlayers[0].xPos, jjLocalPlayers[0].yPos, SOUND::COMMON_SPLUT, 48, 0);
currState = Move;
}
break;
case Move:
obj.var[0] = 7;
facePlayer(obj);
if (!jjMaskedPixel(int(obj.xPos - (32 * obj.direction)), int(obj.yPos), 4) && obj.freeze == 0) {
obj.xPos -= (3 * obj.direction);
}
if (obj.special >= 70) {
if (jjRandom()%rand > 0 && jjRandom()%rand < 3) {
currState = Stand;
obj.special = 0;
obj.frameID = 0;
} else if (jjRandom()%rand == 0) {
currState = Move;
obj.special = 0;
obj.frameID = 0;
} else if (jjRandom()%rand == 3) {
currState = Float;
obj.special = 0;
obj.frameID = 0;
}
}
break;
case Stand:
obj.var[0] = 3;
facePlayer(obj);
if (obj.special >= 35) {
switch(jjRandom()%2) {
case 0:
currState = Scream;
obj.special = 0;
obj.frameID = 0;
break;
case 1:
currState = Stomp;
obj.special = 0;
obj.frameID = 0;
break;
}
facePlayer(obj);
}
break;
case Scream:
obj.var[0] = 0;
if (obj.special == 14) jjSample(jjLocalPlayers[0].xPos, jjLocalPlayers[0].yPos, SOUND::QUEEN_SCREAM, 48, 0);
if (obj.special % 21 == 0 && obj.special >= 14) {
Icicle temp;
jjOBJ@ icicle = jjObjects[jjAddObject(OBJECT::BLASTERBULLET, int(obj.xPos), int(obj.yPos), obj.objectID, CREATOR::OBJECT, jjVOIDFUNCOBJ(temp.onBehave))];
icicle.xSpeed = -8 * obj.direction;
icicle.ySpeed = -(2 + jjRandom()%4);
icicle.direction = -obj.direction;
icicle.counterEnd = 200;
icicle.var[4] = 1;
icicle.state = STATE::FLY;
icicle.playerHandling = HANDLING::ENEMYBULLET;
icicle.lightType = LIGHT::NONE;
}
if (obj.special >= 70) {
randomQueenMove(obj);
facePlayer(obj);
}
break;
case Stomp:
obj.var[0] = 6;
facePlayer(obj);
if (obj.special == 35) jjSample(jjLocalPlayers[0].xPos, jjLocalPlayers[0].yPos, SOUND::COMMON_LAND1, 48, 0);
if (obj.special == 50) jjSample(jjLocalPlayers[0].xPos, jjLocalPlayers[0].yPos, CollapsingIceSounds[jjRandom()%3]);
if (jjRandom()%randcar < (randcar - 1)) {
if (obj.special % 4 == 0 && obj.special >= 42) {
Icicle temp;
jjOBJ@ icicle = jjObjects[jjAddObject(OBJECT::BLASTERBULLET, (20160 + jjRandom()%768), 80*32, obj.objectID, CREATOR::OBJECT, jjVOIDFUNCOBJ(temp.onBehave))];
icicle.xSpeed = 0;
icicle.ySpeed = 6;
icicle.direction = 1;
icicle.counterEnd = 200;
icicle.state = STATE::FLY;
icicle.playerHandling = HANDLING::ENEMYBULLET;
icicle.lightType = LIGHT::NONE;
}
} else {
if (obj.special % 4 == 0 && obj.special >= 42) {
jjOBJ@ carrot = jjObjects[jjAddObject(OBJECT::CARROT, (20160 + jjRandom()%768), 80*32, obj.objectID, CREATOR::OBJECT)];
carrot.state = STATE::FLOATFALL;
}
}
if (obj.special >= 70) {
randomQueenMove(obj);
}
break;
case Float:
obj.var[0] = 5;
facePlayer(obj);
if (obj.freeze == 0) {
if (obj.xPos < 642.5*32) obj.xPos += 2;
else if (obj.xPos > 642.5*32) obj.xPos -= 2;
if (obj.yPos > 89*32) {
obj.yPos -= 2;
obj.special = 0;
} else {
if (obj.special % 7 == 0 && obj.special < 350 && (obj.xPos > 641*32 && obj.yPos < 643*32)) {
Iceball temp;
jjOBJ@ iceball = jjObjects[jjAddObject(OBJECT::BLASTERBULLET, int(obj.xPos + jjSin(jjGameTicks*20)), int(obj.yPos + jjCos(jjGameTicks*20)), obj.objectID, CREATOR::OBJECT, jjVOIDFUNCOBJ(temp.onBehave))];
jjSample(iceball.xPos, iceball.yPos, SOUND::AMMO_ICEGUN, 0, 0);
iceball.counterEnd = 250;
iceball.state = STATE::FLY;
iceball.playerHandling = HANDLING::ENEMYBULLET;
iceball.lightType = LIGHT::NONE;
iceball.xSpeed = (jjSin(jjGameTicks*20)*6) * (jjRandom()%2 > 0? 1:-1);
iceball.ySpeed = (jjCos(jjGameTicks*20)*6) * (jjRandom()%2 > 0? 1:-1);
iceball.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
}
if (obj.special >= 350) {
currState = Fall;
obj.special = 0;
obj.frameID = 0;
}
}
}
break;
}
if (jjLocalPlayers[0].bossActivated) {
jjLocalPlayers[0].boss = obj.objectID;
}
if (obj.state == STATE::FREEZE) {
obj.var[1] = obj.var[1] - 1;
if (obj.var[1] == 0) {
obj.unfreeze(1);
obj.state = obj.oldState;
}
} else {
obj.var[1] = 70;
}
obj.energy = int(obj.age / 1.5);
if (obj.age < 1) {
obj.particlePixelExplosion(0);
obj.delete();
givePlayerPointsForObject(jjLocalPlayers[0], obj);
currPhase = Dying;
jjMusicStop();
jjLocalPlayers[0].bossActivated = false;
}
if (jjGameConnection != GAME::LOCAL || jjLocalPlayerCount > 1) obj.delete();
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bull, jjPLAYER@ play, int force) {
if (bull !is null) {
if (bull.playerHandling == HANDLING::PLAYERBULLET) {
if ((currState == Move || currState == Stand) && bull.var[3] != 9) {
if (bull.xSpeed > 0) {
if (obj.direction == 1) bull.ricochet();
else hurtByBullet(obj, bull);
} else if (bull.xSpeed < 0) {
if (obj.direction == -1) bull.ricochet();
else hurtByBullet(obj, bull);
}
} else {
hurtByBullet(obj, bull);
}
}
if ((bull.var[6] & 16) == 0) {
bull.state = STATE::EXPLODE;
}
} else if (play !is null) {
play.hurt();
}
return true;
}
}
void randomQueenMove(jjOBJ@ obj) {
switch (jjRandom()%rand) {
case 0: currState = Move; break;
case 1: currState = Scream; break;
case 2: currState = Stomp; break;
case 3: currState = Float; break;
}
obj.special = 0;
obj.frameID = 0;
}
void facePlayer(jjOBJ@ obj) {
if (obj.freeze == 0) {
if (jjLocalPlayers[0].xPos > int(obj.xPos + 48)) obj.direction = -1;
else if (jjLocalPlayers[0].xPos < int(obj.xPos - 48)) obj.direction = 1;
}
}
void hurtByBullet(jjOBJ@ obj, jjOBJ@ bull) {
obj.age -= bull.animSpeed;
obj.justHit = 5;
if (obj.freeze > 0) {
obj.unfreeze(1);
obj.age -= bull.animSpeed;
}
}
class QueenBoulder : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::ROTATINGROCK);
obj.age++;
for (int i = 0; i < jjObjectCount; i++) {
if (jjObjects[i].eventID == OBJECT::QUEEN && obj.doesCollide(jjObjects[i], true)) {
obj.xSpeed = -4;
obj.ySpeed = -2;
}
}
if (obj.age == 420) {
obj.particlePixelExplosion(0);
obj.clearPlatform();
obj.delete();
}
}
}
class Icicle : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BULLET, false);
obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
if (obj.state == STATE::EXPLODE) {
obj.unfreeze(1);
obj.delete();
} else {
obj.xAcc = 0;
obj.yAcc = 0;
jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[2], 0, 0, obj.var[0], 1, 1, SPRITE::SINGLEHUE, 128);
if (obj.var[4] == 1) {
obj.ySpeed += 0.15;
}
}
}
}
class Iceball : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BULLET, obj.state == STATE::EXPLODE? true:false);
obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
if (obj.state == STATE::FLY) {
obj.xAcc = 0;
obj.yAcc = 0;
if (obj.ySpeed < 0) obj.ySpeed *= -1;
jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::AMMO, 77, 6, obj.var[0], 0.8, 0.8, SPRITE::SINGLEHUE, 128);
}
}
}
class Bubba : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(!obj.isActive? BEHAVIOR::EXPLOSION2 : inView(obj)? BEHAVIOR::BUBBA : BEHAVIOR::BEE);
if (obj.energy < 1) {
obj.particlePixelExplosion(0);
jjOBJ@ coin = jjObjects[jjAddObject(OBJECT::SILVERCOIN, obj.xPos, obj.yPos)];
coin.state = STATE::FLOATFALL;
for (int i = 0; i < jjLocalPlayerCount; i++) {
givePlayerPointsForObject(jjLocalPlayers[i], obj);
}
obj.delete();
}
}
}
class TuffBoss : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(!obj.isActive? BEHAVIOR::EXPLOSION2 : inView(obj)? BEHAVIOR::TUFBOSS : BEHAVIOR::WALKINGENEMY);
if (obj.energy < 1) {
obj.particlePixelExplosion(0);
jjOBJ@ coin = jjObjects[jjAddObject(OBJECT::SILVERCOIN, obj.xPos, obj.yPos)];
coin.state = STATE::FLOATFALL;
for (int i = 0; i < jjLocalPlayerCount; i++) {
givePlayerPointsForObject(jjLocalPlayers[i], obj);
}
obj.delete();
}
}
}
class HandleMovingPlatforms : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(obj.freeze == 0? BEHAVIOR::BUTTERFLY : BEHAVIOR::WALKINGENEMY, false);
obj.deactivates = false;
}
}
class MovingPlatform : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::PLATFORM);
obj.deactivates = false;
if (jjLocalPlayerCount == 1 && jjLocalPlayers[0].health == 0) obj.delete();
for (int i = 0; i < jjObjectCount; i++) {
if (jjObjects[i].eventID == OBJECT::BUTTERFLY) {
float dx = jjObjects[i].xPos - obj.xPos, dy = jjObjects[i].yPos - obj.yPos;
if (dx * dx + dy * dy < 64 * 64) {
obj.xOrg = jjObjects[i].xPos;
obj.yOrg = jjObjects[i].yPos;
obj.xPos = jjObjects[i].xPos;
obj.yPos = jjObjects[i].yPos;
jjObjects[i].freeze = obj.freeze;
}
}
}
}
}
class PurpleJazz : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ pj) {
pj.behave(BEHAVIOR::PICKUP, false);
pj.direction = -1;
pj.var[1] = jjIsTSF? 30:33;
pj.var[2] = jjIsTSF? 55:70;
jjDrawSprite(pj.xPos, pj.yPos, ANIM::JAZZ, pj.var[0] == 1? pj.var[2] : pj.var[1], pj.var[0] == 1? jjGameTicks >> 2 : 0, pj.direction, SPRITE::PLAYER, 31);
if (cutsceneTime >= 2017) {
pj.xPos -= 6;
pj.var[0] = 1;
if (pj.xPos < jjLocalPlayers[0].xPos) jjLocalPlayers[0].direction = -1;
}
if (cutsceneTime == 2060) {
for (int i = 0; i < jjObjectCount; i++) {
if (jjObjects[i].eventID == OBJECT::ONEUPCRATE && jjObjects[i].xOrg > 654*32) {
jjObjects[i].xPos = pj.xPos;
jjObjects[i].yPos = 28.75*32;
}
}
}
if (pj.xPos < 636*32) pj.delete();
}
}
void onFunction0() {
blizzard = true;
}
void onFunction1() {
blizzard = false;
}
void onFunction2(jjPLAYER@ play) {
if (jjGameConnection == GAME::LOCAL) {
for (int i = 0; i < jjObjectCount; i++) {
if (jjObjects[i].eventID == OBJECT::QUEEN) {
if (currPhase == None) {
play.showText("@@@@Who dares enter the Ice Queen's lair?@You shall perish, foolish rabbit!");
jjMusicLoad("Boss.s3m", false);
currPhase = PhaseOne;
}
play.cameraFreeze(577.5*32, jjLocalPlayerCount > 1? 30.5*32 : 27.5*32, true, false);
}
}
} else {
jjAlert("|No boss in online coop, sorry :(");
jjNxt("HH17_Level07.j2l", true, false);
}
}
void onFunction3() {
if (!cutsceneComplete) cutscene = true;
}
void onFunction4() {
if (cutsceneComplete) jjTriggers[29] = 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.