Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Candy Goth | Violet CLM | Single player | 8.3 |
const bool MLLESetupSuccessful = MLLE::Setup(); ///@MLLE-Generated
#include "MLLE-Include-1.5.asc" ///@MLLE-Generated
#pragma require "CandyGothDecs.j2t" ///@MLLE-Generated
#pragma require "PezroxV.j2t" ///@MLLE-Generated
#pragma require "CandyGoth.j2l" ///@MLLE-Generated
#pragma require "SkullGem.j2a"
#pragma require "Lubella.j2a"
#pragma offer "beyond_-_creepy.it"
uint FirstTileFrameID;
void onLevelLoad() {
jjAnimations[jjObjectPresets[OBJECT::REDGEM].curAnim] = jjAnimations[jjAnimSets[ANIM::CUSTOM[0]].load(0, "SkullGem.j2a")];
Blacken(OBJECT::BAT);
Blacken(OBJECT::RAVEN);
Blacken(OBJECT::DEMON);
jjTexturedBGTexture = TEXTURE::WISETYNESS;
jjTexturedBGFadePositionY = 0.6;
jjUseLayer8Speeds = true;
const array<array<int>> tileSpriteDimensions = {
{0,0, 16,32*5-4, 0,-9},
{16,0, 16,32*5-4, 0,-9},
{0, 15*32, 64,32, -32,-32},
{0, 16*32, 64,32, -32,0},
{0, 17*32, 9,28, -5,-14},
{0,0, 96,16, 0,0},
{1*32, 17*32, 32,32, -16,-16},
{0, 9*32, 64,64, -32,-32},
{2*32, 7*32, 128,128, -64,-64},
{0, 18*32, 64,16, -32,0}
};
FirstTileFrameID = jjAnimations[jjAnimSets[ANIM::CUSTOM[1]].allocate(array<uint>={tileSpriteDimensions.length})];
for (uint i = 0; i < tileSpriteDimensions.length; ++i) {
jjANIMFRAME@ tileFrame = jjAnimFrames[FirstTileFrameID + i];
const auto@ dimensions = tileSpriteDimensions[i];
jjPIXELMAP(dimensions[0],dimensions[1],dimensions[2],dimensions[3], 5).save(tileFrame);
tileFrame.hotSpotX = dimensions[4];
tileFrame.hotSpotY = dimensions[5];
}
///@Event 141=Lower Floor |+|Trigger |Lower|Floor|TriggerID:5
jjObjectPresets[141].behavior = LoweringFloor;
jjObjectPresets[141].playerHandling = HANDLING::PARTICLE;
jjObjectPresets[141].curFrame = FirstTileFrameID;
jjObjectPresets[141].isBlastable = false;
///@Event 143=Rippling Floor |+|Trigger |Ripple|Floor
jjObjectPresets[143].behavior = RipplingFloor;
jjObjectPresets[143].playerHandling = HANDLING::PARTICLE;
jjObjectPresets[143].curFrame = FirstTileFrameID;
jjObjectPresets[143].deactivates = false;
jjObjectPresets[143].isBlastable = false;
if (jjAnimSets[ANIM::BRIDGE] != 0) {
jjObjectPresets[OBJECT::BRIDGE].behavior = BridgeWrapper;
jjANIMATION@ bridgeAnim = jjAnimations[jjAnimSets[ANIM::BRIDGE]];
bridgeAnim.firstFrame = FirstTileFrameID;
bridgeAnim.frameCount = 2;
}
///@Event 142=Pentagram |+|Goodies |Pent-|agram|EventID:8|Down:c1
jjObjectPresets[142].behavior = Pentagram;
jjObjectPresets[142].playerHandling = HANDLING::PARTICLE;
jjObjectPresets[142].curFrame = FirstTileFrameID + 2;
///@Event 146=Collapsible Platform |+|Trigger |Collapse|Plat|TriggerID:5
jjObjectPresets[146].behavior = CollapsiblePlatform;
jjObjectPresets[146].playerHandling = HANDLING::PARTICLE;
jjObjectPresets[146].curFrame = FirstTileFrameID + 5;
jjObjectPresets[146].isBlastable = false;
///@Event 147=Void |+|Scenery |Void
jjObjectPresets[147].behavior = Void();
jjObjectPresets[147].playerHandling = HANDLING::SPECIAL;
jjObjectPresets[147].scriptedCollisions = true;
jjObjectPresets[147].curFrame = FirstTileFrameID + 6;
jjObjectPresets[147].isFreezable = false;
jjObjectPresets[147].triggersTNT = false;
jjObjectPresets[147].isBlastable = false;
jjAnimations[jjObjectPresets[OBJECT::SPIKEBOLL].curAnim].firstFrame = FirstTileFrameID + 8;
jjObjectPresets[OBJECT::SPIKEBOLL].behavior = Choker2D;
if (jjAnimSets[ANIM::ROCK] == 0) jjAnimSets[ANIM::ROCK].load(); //for the sound effect
jjObjectPresets[OBJECT::SPIKEBOLL].deactivates = false;
///@Event 170=Choker Scenery |+|Trigger |Choke|Scen
jjObjectPresets[170].behavior = ChokerScenery;
jjObjectPresets[170].playerHandling = HANDLING::PARTICLE;
jjObjectPresets[170].determineCurAnim(ANIM::DESTSCEN, 2);
jjObjectPresets[170].curFrame = jjAnimations[jjObjectPresets[170].curAnim];
jjObjectPresets[170].deactivates = false; //meh
///@Event 177=Lubella |-|Boss |Lubella
jjObjectPresets[177].behavior = Lubella();
jjObjectPresets[177].playerHandling = HANDLING::PARTICLE; //while wating for activation
jjObjectPresets[177].bulletHandling = HANDLING::DETECTBULLET;
jjObjectPresets[177].scriptedCollisions = true;
jjObjectPresets[177].determineCurAnim(ANIM::DESTSCEN, 2);
jjObjectPresets[177].frameID = 0;
jjObjectPresets[177].curFrame = jjAnimations[jjAnimSets[ANIM::CUSTOM[2]].load(0, "Lubella.j2a")];
jjObjectPresets[177].isFreezable = true;
jjObjectPresets[177].triggersTNT = true;
jjObjectPresets[177].isBlastable = true;
jjObjectPresets[177].isTarget = true;
jjObjectPresets[177].energy = 100;
jjObjectPresets[OBJECT::GRASSPLATFORM].behavior = ForceWheel;
jjObjectPresets[OBJECT::GRASSPLATFORM].playerHandling = HANDLING::PARTICLE;
jjObjectPresets[OBJECT::GRASSPLATFORM].xAcc = jjObjectPresets[OBJECT::GRASSPLATFORM].yAcc = 0;
jjObjectPresets[OBJECT::GRASSPLATFORM].deactivates = false;
jjAnimations[jjObjectPresets[OBJECT::SPIKEBOLL3D].curAnim].firstFrame = FirstTileFrameID + 9;
jjObjectPresets[OBJECT::SPIKEBOLL3D].behavior = Platform3D;
jjObjectPresets[OBJECT::SPIKEBOLL3D].playerHandling = HANDLING::PARTICLE; //shooting can get it confused, so let's not bother
jjObjectPresets[21].behavior = Teleportal;
jjObjectPresets[21].playerHandling = HANDLING::PARTICLE;
}
void onLevelReload() {
MLLE::Palette.apply();
ImmobilizePlayers = false;
jjMusicLoad("cute.mod");
}
class Blacken : jjBEHAVIORINTERFACE {
jjBEHAVIOR behavior;
Blacken(OBJECT::Object eventID) {
jjOBJ@ preset = jjObjectPresets[eventID];
behavior = preset.behavior;
preset.behavior = this;
preset.lightType = LIGHT::NORMAL;
preset.light = 10;
}
void onBehave(jjOBJ@ obj) {
obj.behave(behavior, false);
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, obj.freeze == 0 ? SPRITE::SINGLECOLOR : SPRITE::FROZEN, obj.justHit == 0 ? 0 : 15);
}
}
void LoweringFloor(jjOBJ@ obj) {
obj.xPos = obj.xOrg;
if (obj.state == STATE::START) {
if (obj.creator == CREATOR::LEVEL) {
obj.xOrg = obj.xPos -= 15;
obj.yPos -= 11;
obj.var[0] = jjAddObject(obj.eventID, obj.xPos + 16, obj.yPos);
} else {
obj.deactivates = false;
obj.curFrame += 1;
}
obj.var[1] = jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0, 5);
obj.state = STATE::WAIT;
} else if (obj.state == STATE::DEACTIVATE) {
jjDeleteObject(obj.var[0]);
obj.deactivate();
} else if (obj.state == STATE::WAIT) {
if (jjTriggers[obj.var[1]])
obj.state = STATE::FALL;
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ play = jjLocalPlayers[i];
if (play.yPos > obj.yPos - 22 && play.yPos < obj.yPos + 160 && abs(obj.xPos - play.xPos) < 8) {
play.yPos = obj.yPos - 23;
play.xPos += 1;
}
}
obj.bePlatform(obj.xPos, obj.yPos);
} else {
if (int(obj.yPos) & 31 == 4 && jjMaskedHLine(int(obj.xPos), 16, int(obj.yPos - 4))) {
obj.clearPlatform();
obj.delete();
} else {
obj.yPos += 1;
obj.bePlatform(obj.xPos, obj.yPos - 1);
}
}
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos + 5, obj.curFrame);
}
uint NumberOfPrayers = 0; //static
void Pentagram(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.yPos -= 15;
obj.state = STATE::WAIT;
if (jjParameterGet(uint(obj.xOrg) >> 5, (uint(obj.yOrg) >> 5), 8, 1) == 1)
obj.yPos += 32;
} else if (obj.state == STATE::DEACTIVATE) {
obj.deactivate();
} else if (obj.state == STATE::WAIT) {
bool beingKneltOn = false;
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ play = jjLocalPlayers[i];
if (play.keyDown && play.curAnim - jjAnimSets[play.setID] == RABBIT::DIVE && abs(obj.xPos - play.xPos) < 15 && abs(obj.yPos - play.yPos) < 30) {
beingKneltOn = true;
break;
}
}
if (beingKneltOn) {
if (obj.counter < 0)
obj.counter = 50;
else if (++obj.counter == 100) {
NumberOfPrayers += 1;
bool deleteMe = true;
jjSample(obj.xPos, obj.yPos, SOUND::DEVILDEVAN_DRAGONFIRE);
const uint8 eventID = jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0, 8);
if (eventID == OBJECT::BOMB) {
jjOBJ@ bomb = jjObjects[jjAddObject(OBJECT::BOMB, obj.xPos, obj.yPos - 16, obj.objectID, CREATOR::OBJECT, BombWrapper)];
bomb.ySpeed = -4;
bomb.state = STATE::FLY;
if (jjAnimSets[ANIM::LIZARD] != 0)
bomb.curAnim = jjAnimSets[ANIM::LIZARD] + 1;
deleteMe = false;
} else if (eventID == AREA::TRIGGERZONE) {
jjTriggers[jjParameterGet(uint(obj.xOrg) >> 5, (uint(obj.yOrg) >> 5) - 1, 0, 5)] = true;
} else {
jjOBJ@ spawn = jjObjects[jjAddObject(eventID, obj.xPos, obj.yPos - 16, obj.objectID, CREATOR::OBJECT)];
if (spawn.behavior == BEHAVIOR::PICKUP) {
spawn.var[2] = 30;
spawn.ySpeed = -4;
spawn.xSpeed = 1;
spawn.objType = HANDLING::DELAYEDPICKUP;
} else if (spawn.behavior == BEHAVIOR::SPRING) {
deleteMe = false;
obj.state = STATE::FADEOUT; //invisible, but can be deactivated
} else if (eventID == 21) //teleportal
deleteMe = false;
}
if (deleteMe)
obj.delete();
else
obj.counter = 0;
} else {
const uint rand = jjRandom();
if (rand & 0x8000 != 0) {
jjAddObject(obj.eventID, obj.xPos - 32 + (rand & 63), obj.yPos - 16 + ((rand >> 6) & 31), obj.objectID, CREATOR::OBJECT, PentagramMagic);
}
}
} else if (NumberOfPrayers < 3) {
if (--obj.counter < -400 && obj.counter & 7 < 4) {
for (int i = 0; i < jjLocalPlayerCount; ++i) {
const jjPLAYER@ play = jjLocalPlayers[i];
const jjANIMATION@ anim = jjAnimations[jjAnimSets[play.setID] + RABBIT::DIVE];
const int playerID = play.playerID;
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos - 20, anim.firstFrame + anim.frameCount - 1, 1, SPRITE::TRANSLUCENTPLAYER, playerID, 3,4, playerID);
}
}
}
}
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, 1, SPRITE::ALPHAMAP, 29, 4);
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame + 1, 1, SPRITE::ALPHAMAP, 29, 3);
}
void PentagramMagic(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.curFrame += 2;
obj.state = STATE::FLOAT;
}
if (jjRandom() & 31 == 0)
obj.delete();
else
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos -= 2, obj.curFrame, 1, SPRITE::ALPHAMAP, 29, 3);
}
void BombWrapper(jjOBJ@ obj) {
if (obj.state == STATE::START)
obj.playerHandling = HANDLING::PARTICLE;
else if (obj.ySpeed > 1 && obj.playerHandling == HANDLING::PARTICLE)
obj.playerHandling = HANDLING::SPECIAL;
obj.behave(BEHAVIOR::BOMB);
if (obj.state == STATE::EXPLODE && obj.counter == 1) {
for (int otherObjectID = jjObjectCount; --otherObjectID != 0;) {
jjOBJ@ other = jjObjects[otherObjectID];
if (other.behavior == RipplingFloor && abs(obj.xPos - 8 - other.xPos) < 16)
other.state = STATE::BOUNCE;
}
}
}
void BridgeWrapper(jjOBJ@ obj) {
obj.xPos += 1;
obj.behavior = BEHAVIOR::BRIDGE;
obj.behave();
}
void RipplingFloor(jjOBJ@ obj) {
if (obj.state == STATE::START) {
if (obj.creator == CREATOR::LEVEL) {
obj.xPos -= 15;
} else {
obj.var[0] = obj.creatorID;
if (int(obj.xPos) & 31 == 16)
obj.curFrame += 1;
}
obj.yPos -= 11;
if (!jjMaskedPixel(int(obj.xPos) + 16, int(obj.yPos)) || jjTileGet(4, (int(obj.xPos) + 16) >> 5, int(obj.yOrg) >> 5) == 552)
obj.var[1] = jjAddObject(obj.eventID, obj.xPos + 16, obj.yOrg, obj.objectID);
obj.state = STATE::WAIT;
} else if (obj.state == STATE::DEACTIVATE) {
//jjDeleteObject(obj.var[0]);
//obj.deactivate();
} else {
const auto lastY = obj.yPos;
if (obj.state == STATE::BOUNCE) {
obj.yPos = obj.yOrg - 11 + jjSin(obj.counter += 16) * 26;
if (obj.counter == 1024) {
obj.counter = 0;
obj.state = STATE::WAIT;
} else if (obj.counter == 48) {
for (uint i = 0 ; i < 2; ++i)
if (obj.var[i] != 0) {
jjOBJ@ other = jjObjects[obj.var[i]];
if (other.state == STATE::WAIT)
other.state = STATE::BOUNCE;
}
} else if (obj.counter == 768 - 64) { //highest point
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ play = jjLocalPlayers[i];
if (play.platform == obj.objectID) {
const auto realCurFrame = obj.curFrame;
obj.ySpeed = -25;
obj.special = CREATOR::PLAYER;
obj.state = STATE::SPRING;
obj.behave(BEHAVIOR::SPRING, false);
obj.state = STATE::BOUNCE;
obj.curFrame = realCurFrame;
}
}
}
}
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ play = jjLocalPlayers[i];
if (play.yPos > obj.yPos - 22 && play.yPos < obj.yPos + 160 && abs(obj.xPos - play.xPos) < 8) {
play.yPos = obj.yPos - 23;
play.xPos += 1;
}
}
obj.bePlatform(obj.xPos, lastY);
}
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos + 5, obj.curFrame, 1, SPRITE::NORMAL,0, 5);
}
void CollapsiblePlatform(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.xPos -= 15;
obj.yPos -= 11;
obj.state = STATE::WAIT;
obj.counter = 30;
if (obj.creator == CREATOR::LEVEL)
obj.var[0] = jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0, 5);
} else if (obj.state == STATE::DEACTIVATE) {
obj.deactivate();
} else {
if (obj.counter >= 6) {
obj.bePlatform(obj.xPos, obj.yPos);
if (obj.counter == 30) {
if (obj.var[0] == 0)
for (int i = 0; i < jjLocalPlayerCount; ++i) {
const jjPLAYER@ play = jjLocalPlayers[i];
if (play.platform == obj.objectID) {
obj.counter = 29;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_COLLAPS);
break;
}
}
else if (jjTriggers[obj.var[0]])
obj.counter = 29;
}
} else
obj.clearPlatform();
for (int x = 0; x < 6; ++x)
for (int y = 0; y < 4; ++y) {
const int position = x + y*6;
const uint16 tileID = 1 + (x>>1) + (y>>1)*10;
const TILE::Quadrant quadrant = TILE::Quadrant((x&1) + ((y&1)<<1));
const float xPos = obj.xPos + (x<<4), yPos = obj.yPos + (y<<4) - 4;
if (position < obj.counter)
jjDrawTile(xPos, yPos, tileID, quadrant);
else if (position == obj.counter && jjGameTicks & 1 == 0) {
jjPARTICLE@ fragment = jjAddParticle(PARTICLE::TILE);
if (fragment !is null) {
fragment.xPos = xPos;
fragment.yPos = yPos;
fragment.tile.tileID = tileID;
fragment.tile.quadrant = quadrant;
fragment.xSpeed = (x - 2.5) / 6;
}
}
}
if (obj.counter < 30 && jjGameTicks & 1 == 1 && --obj.counter < 0)
obj.delete();
}
}
class Void : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.state = STATE::FADEIN;
obj.xAcc = 0; //scale
obj.special = jjRandom();
if (obj.creatorType == CREATOR::LEVEL) {
int childID = 0;
for (int x = -1; x <= 1; x += 2)
for (int y = -1; y <= 1; y += 2)
obj.var[childID++] = jjAddObject(obj.eventID, obj.xOrg + (x<<3), obj.yOrg + (y<<3));
}
const float scale = (jjTileGet(4, int(obj.xOrg)>>5, int(obj.yOrg)>>5) != 592) ? 1.0f : 2.5f;
obj.xPos += (int(jjRandom() & 7) - 3.5) * scale;
obj.yPos += (int(jjRandom() & 7) - 3.5) * scale;
} else if (obj.state == STATE::DEACTIVATE) {
obj.deactivate();
} else if (obj.state == STATE::FADEOUT) {
if (obj.xAcc > 0)
obj.xAcc -= 0.125;
else if (obj.xSpeed == 0 && obj.ySpeed == 0)
obj.state = STATE::FADEIN;
else
obj.delete();
} else if (obj.state == STATE::FADEIN) {
if (obj.counter != 0)
--obj.counter;
else if (obj.xAcc < 1)
obj.xAcc += 0.125;
else {
obj.state = STATE::ROTATE;
obj.playerHandling = HANDLING::SPECIAL;
}
} else if (obj.state == STATE::ROTATE) {
obj.special += 3;
}
if (obj.xAcc > 0) {
jjDrawResizedSpriteFromCurFrame(obj.xPos + jjSin(obj.special) * 3, obj.yPos + jjCos(obj.special) * 3, obj.curFrame, obj.xAcc,obj.xAcc, SPRITE::ALPHAMAP, 0, 2);
if (obj.xSpeed != 0 || obj.ySpeed != 0) {
obj.xPos += obj.xSpeed;
obj.yPos += obj.ySpeed;
if (++obj.age > 1100)
obj.delete();
}
}
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
if (bullet is null) {
player.hurt();
} else {
obj.state = STATE::FADEOUT;
obj.playerHandling = HANDLING::PARTICLE;
obj.counter = 110 + (3 - jjDifficulty) * 30;
if (bullet.freeze != 0) //ice
obj.counter += 55;
}
return true;
}
}
void Choker2D(jjOBJ@ obj) {
int angle;
const SPRITE::Mode mode = (obj.freeze == 0) ? SPRITE::NORMAL : SPRITE::FROZEN;
if (obj.state == STATE::KILL) {
auto xSpeed = obj.xSpeed * 2, ySpeed = obj.ySpeed * 2;
if (xSpeed >= 0) {
if (xSpeed < 1.5)
xSpeed = 1.5;
} else if (xSpeed > -1.5)
xSpeed = -1.5;
obj.behave(BEHAVIOR::PLATFORM, false); //make chain fragments
obj.energy = 0;
obj.state = STATE::FLY;
obj.xSpeed = xSpeed;
obj.ySpeed = ySpeed;
obj.playerHandling = HANDLING::SPECIAL;
obj.behavior = Choker2D; //still!
return;
} else if (obj.energy <= 0) {
if (obj.yPos > 2050) { //fell out of the level
obj.delete();
} else {
const auto lastX = abs(obj.xSpeed);
const auto lastY = obj.ySpeed;
obj.behave(BEHAVIOR::ROTATINGROCK, false);
if (abs(obj.xSpeed) < lastX) {
obj.xSpeed = (obj.xSpeed >= 0) ? lastX : -lastX;
}
if (jjEventGet(uint(obj.xPos) >> 5, uint(obj.yPos) >> 5) == AREA::PATH) {
if ((obj.xSpeed >= 0) != (jjParameterGet(uint(obj.xPos) >> 5, uint(obj.yPos) >> 5, 0,1) == 0))
obj.xSpeed = -obj.xSpeed;
}
if (obj.state == STATE::DONE) {
obj.ySpeed = lastY;
obj.state = STATE::FLY;
}
angle = obj.var[0] / 2;
obj.deactivates = false;
//this would work fine if available for ::PLATFORM chokers too, except that the level layout offers no such opportunities.
for (int otherObjectID = jjObjectCount; --otherObjectID != 0;) {
jjOBJ@ other = jjObjects[otherObjectID];
if (other.behavior == ChokerScenery && other.state == STATE::IDLE && other.doesCollide(obj))
other.state = STATE::KILL;
}
}
} else {
const auto lastX = obj.xPos, lastY = obj.yPos;
obj.behave(BEHAVIOR::PLATFORM, false);
const int chainFrameID = jjAnimations[obj.killAnim];
const int radadd=jjAnimFrames[chainFrameID].width-1;
const int angleadd = -obj.var[5];
int radius = 0;
angle = obj.var[4] - angleadd * obj.var[2];
for (int n = 0; n < obj.var[2]; ++n) {
jjDrawSpriteFromCurFrame(
obj.xOrg + radius * jjSin(angle),
obj.yOrg + radius * jjCos(angle),
chainFrameID, 1,
mode
);
angle += angleadd;
radius += radadd;
};
radius += radadd * 2;
obj.xPos = obj.xOrg + radius * jjSin(angle);
obj.yPos = obj.yOrg + radius * jjCos(angle);
obj.xSpeed = obj.xPos - lastX;
obj.ySpeed = obj.yPos - lastY;
}
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -angle << 1, 1,1, mode);
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame - 1, 1, mode);
}
void ChokerScenery(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.state = STATE::IDLE;
obj.var[0] = int(obj.xPos) >> 5;
obj.var[1] = int(obj.yPos) >> 5;
obj.var[2] = jjTileGet(4, obj.var[0], obj.var[1]);
const auto@ frames = jjTiles[obj.var[2]].getFrames();
obj.var[3] = frames.length <= 1 ? 0 : frames[1];
obj.var[4] = frames[(frames.length > 2) ? (frames.length - 1) : 0];
} else if (obj.state == STATE::KILL) {
jjAddParticleTileExplosion(obj.var[0], obj.var[1], obj.var[4], false);
jjTileSet(4, obj.var[0], obj.var[1], obj.var[3]);
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_DAMPED1);
obj.state = STATE::DONE;
obj.deactivates = false;
} else if (obj.state == STATE::DEACTIVATE) {
if (jjDeactivatingBecauseOfDeath)
jjTileSet(4, obj.var[0], obj.var[1], obj.var[2]);
obj.deactivate();
}
}
int DesiredModSpeed;
class Lubella : jjBEHAVIORINTERFACE {
jjPLAYER@ nearestPlayer(const jjOBJ@ obj) const {
return jjPlayers[obj.findNearestPlayer(0x7FFFFFFF)];
}
void onBehave(jjOBJ@ obj) {
if (obj.justHit == 0 && obj.doesHurt > 1) {
obj.justHit = (obj.doesHurt -= 2);
}
//breathing counter:
++obj.age;
if (obj.state != STATE::FREEZE) {
if (obj.state == STATE::ATTACK || obj.state == STATE::FIRE) {
if (obj.frameID < 15) {
obj.frameID += 1;
obj.yPos -= 1;
obj.yOrg -= 1;
}
} else {
if (obj.frameID > 0) {
obj.frameID -= 1;
obj.yPos += 1;
obj.yOrg += 1;
}
}
}
if (obj.energy < 100 && jjGetModSpeed() != DesiredModSpeed)
jjSetModSpeed(DesiredModSpeed);
switch (obj.state) {
case STATE::START:
obj.state = STATE::DELAYEDSTART;
obj.var[1] = 75; //next energy point to descend at
obj.yPos += 200;
return;
case STATE::DELAYEDSTART:
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ localPlayer = jjLocalPlayers[i];
if (localPlayer.bossActivated) {
localPlayer.boss = obj.objectID;
obj.state = STATE::FADEIN;
break;
}
}
return;
case STATE::DEACTIVATE:
obj.deactivate(); //sure
return;
case STATE::FREEZE:
if (--obj.freeze == 0) {
obj.unfreeze(0);
obj.state = obj.oldState;
}
return;
case STATE::FADEIN:
obj.yPos = obj.yOrg + 200 - jjSin(obj.counter += 4) * 256;
if (obj.counter >= 256) {
obj.justHit = 3;
obj.var[0] = 1;
if (obj.counter == 360) {
obj.playerHandling = HANDLING::SPECIAL;
obj.state = STATE::WALK;
obj.doesHurt = 10;
obj.counter = 0;
jjSample(obj.xPos, obj.yPos, SOUND::PICKUPS_BOING_CHECK);
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ localPlayer = jjLocalPlayers[i];
if (localPlayer.doesCollide(obj)) {
localPlayer.hurt();
localPlayer.yPos = obj.yPos - 25;
localPlayer.ballTime = 50;
}
}
}
}
return;
case STATE::FADEOUT:
obj.yPos = obj.yOrg + 200 - jjSin(obj.counter -= 4) * 256;
if (obj.counter <= 256) {
obj.var[0] = 0;
obj.justHit = 4;
if (obj.counter == 0) {
obj.state = STATE::DUCK;
obj.playerHandling = HANDLING::PARTICLE;
}
}
return;
case STATE::DUCK:
if (obj.energy <= 0) {
obj.state = STATE::DONE;
jjNxt();
} else if (++obj.counter == 700) {
obj.counter = 0;
obj.state = STATE::FADEIN;
} else {
if (obj.var[1] != 50 && obj.counter < 80 && obj.counter & 3 == 1)
jjAddObject(OBJECT::BAT, obj.xPos - 32 + ((obj.counter & 15) << 4), obj.yPos + ((obj.counter >> 4) << 5), (obj.special < 0) ? 2 : 0, CREATOR::OBJECT, BossBat);
if (obj.var[1] != 25 && obj.counter & 63 == 5) {
const jjPLAYER@ target = nearestPlayer(obj);
jjAddObject(OBJECT::SPIKEBOLL, target.xPos, target.cameraY - 130, obj.objectID, CREATOR::OBJECT, BossChoker);
}
}
break;
case STATE::WALK:
if (obj.energy <= obj.var[1]) { //regular (health-based) lowering intervals
obj.var[1] = obj.var[1] - 25;
obj.counter = 360;
obj.state = STATE::FADEOUT;
DesiredModSpeed -= 1;
} else if (++obj.counter >= 165 - (jjDifficulty * 15)) { //attack patterns
obj.counter = 0;
obj.counterEnd = 0;
if ((obj.var[2] = obj.var[2] ^ 1) == 1) {
obj.state = STATE::ATTACK;
if ((obj.var[3] = (obj.var[3] + 1) % 3) == 2) //attack both sides
obj.var[4] = obj.var[6] = 1;
else { //attack player only
const jjPLAYER@ play = nearestPlayer(obj);
obj.var[4] = (play.xPos < obj.xPos) ? 1 : 0;
obj.var[6] = obj.var[4] ^ 1;
}
} else {
obj.state = STATE::FIRE;
}
}
break;
case STATE::ATTACK:
if (obj.counterEnd < 92)
obj.counterEnd += 1;
else if (++obj.counter == 320) {
obj.state = STATE::WALK;
obj.counter = 0;
} else if (obj.counter > 40 && obj.counter & 15 == 0) {
const auto headYPos = obj.yPos - 66 - 92 + jjSin(obj.age << 2) * 3;
for (int hornDir = -1; hornDir <= 1; hornDir += 2)
if (obj.var[5 + hornDir] == 1)
for (int dec = 0; dec < 8; ++dec) {
jjOBJ@ bullet = jjObjects[jjAddObject(OBJECT::FIREBALLBULLETPU, obj.xPos + (38 + dec * 8) * hornDir, headYPos - dec * 7, obj.objectID)];
bullet.xPos = bullet.xOrg;
bullet.ySpeed = 5;
bullet.xSpeed = (dec + 1) * 0.7 * hornDir;
bullet.xAcc = bullet.yAcc = 0;
bullet.playerHandling = HANDLING::ENEMYBULLET;
bullet.animSpeed = (jjDifficulty != 0) ? 2 : 1;
}
}
return;
case STATE::FIRE:
if (++obj.counter == 520) {
obj.state = STATE::WALK;
obj.counter = 0;
} else if ((obj.counterEnd += (1 << jjDifficulty)) == 240) {
const jjPLAYER@ play = nearestPlayer(obj);
const auto spawnY = obj.yPos - 50;
const auto angle = atan2(play.yPos - spawnY, play.xPos - obj.xPos);
const float xSpeed = cos(angle) * 3;
const float ySpeed = sin(angle) * 3;
jjOBJ@ voidHub = jjObjects[jjAddObject(147, obj.xPos, spawnY, obj.objectID, CREATOR::LEVEL)];
voidHub.xSpeed = xSpeed;
voidHub.ySpeed = ySpeed;
for (int i = 0; i < 4; ++i) {
jjOBJ@ voidChild = jjObjects[voidHub.var[i]];
voidChild.xSpeed = xSpeed;
voidChild.ySpeed = ySpeed;
}
}
return;
case STATE::DONE:
obj.yPos += 1;
return;
}
//if break instead of return, track you horizontally/adjust hair angle:
const jjPLAYER@ play = nearestPlayer(obj);
if (play.xPos > obj.xPos + 70) {
obj.xPos += 0.5;
if (obj.special > -9)
obj.special -= 1;
} else if (play.xPos < obj.xPos + -70) {
obj.xPos -= 0.5;
if (obj.special < 9)
obj.special += 1;
} else if (obj.special > 0)
obj.special -= 1;
else if (obj.special < 0)
obj.special += 1;
}
void onDraw(jjOBJ@ obj) {
const bool isFrozen = obj.freeze != 0;
const SPRITE::Mode mode = !isFrozen ? SPRITE::NORMAL : SPRITE::FROZEN;
float yBreathing = jjSin(obj.age << 2);
const auto titsYPos = obj.yPos - obj.justHit - yBreathing * 4;
if (isFrozen) yBreathing = 0;
const auto hairYPos = obj.yPos - 136 + (!isFrozen ? (jjSin((obj.age << 2) - 96) * 6) : 0);
for (int hairFrameID = 3; hairFrameID <= 8; hairFrameID += 5)
jjDrawRotatedSpriteFromCurFrame(obj.xPos, hairYPos, obj.curFrame + hairFrameID, obj.special,1,1, mode,0, 5); //hair
const auto state = (obj.state != STATE::FREEZE) ? obj.state : obj.oldState;
const bool summoningArms = state == STATE::FIRE && obj.counter > 16;
const auto armY = obj.yPos - 30;
for (int armDir = -1; armDir <= 1; armDir += 2) {
const bool hornyArm = state == STATE::ATTACK && obj.var[5 + armDir] == 1;
const int armAngle =
!summoningArms ?
!hornyArm ?
(16 + int(yBreathing * 16) /*+ (!isFrozen ? (obj.justHit << 1) : 0)*/) :
((50 - int(abs(int(obj.counterEnd) - 50))) * 7 + (obj.counterEnd == 92 ? int(yBreathing * 6) : 0)) :
(64 + int(yBreathing * 7));
const int armFrame = obj.curFrame + (!summoningArms && !hornyArm ? 2 : 9);
const auto armX = obj.xPos + 28 * armDir;
jjDrawRotatedSpriteFromCurFrame(armX, armY, armFrame, armDir * armAngle, armDir,1, mode,0, 5);
if (summoningArms || hornyArm) {
const float sin = jjSin(armAngle);
const float cos = jjCos(armAngle);
jjDrawRotatedSpriteFromCurFrame(armX + (cos*23 + sin*53) * armDir, armY + (sin*-23 + cos*53), armFrame + 1, -armDir * (summoningArms ? ((armAngle * 3) - int(abs(int(obj.counterEnd) - 128))) : (armAngle >> 1)), -armDir,1, mode,0, 4);
}
}
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame + 1, 0, mode,0, 5); //torso
const auto headYPos = obj.yPos - 66 + yBreathing * 3;
const bool frowning = obj.justHit != 0 && !isFrozen; //maybe
if (!frowning) {
jjDrawSpriteFromCurFrame(obj.xPos, headYPos, obj.curFrame + 5, 0, mode,0, 5); //eye holes
if (!isFrozen) {
const auto eyeYPos = headYPos - 35;
const jjPLAYER@ play = nearestPlayer(obj);
for (int i = -18; i <= 18; i += 36) {
const auto eyeXPos = obj.xPos + i;
const auto eyeAngle = atan2(play.yPos - eyeYPos, play.xPos - eyeXPos);
jjDrawSpriteFromCurFrame(eyeXPos + cos(eyeAngle) * 6, eyeYPos + sin(eyeAngle) * 6, obj.curFrame + 6, i, SPRITE::NORMAL,0, 5);
}
}
}
jjDrawSpriteFromCurFrame(obj.xPos, headYPos, obj.curFrame + 4, 0, mode,0, 5); //head
if (frowning)
jjDrawSpriteFromCurFrame(obj.xPos, headYPos, obj.curFrame + 7, 0, mode,0, 5); //grouchy face
if (state == STATE::ATTACK && obj.counterEnd > 40) {
for (int hornDir = -1; hornDir <= 1; hornDir += 2)
if (obj.var[5 + hornDir] == 1)
for (int dec = 0; dec < 8; ++dec) {
const float scale = 1.35 - dec * 0.05;
jjDrawRotatedSpriteFromCurFrame(obj.xPos + (38 + dec * 8) * hornDir, headYPos - 92 - dec * 7, obj.curFrame + 11, (30 + dec * 7) * hornDir, hornDir * scale, scale, !isFrozen ? SPRITE::BRIGHTNESS : SPRITE::FROZEN, 128 - (dec << 3), 5);
}
}
const bool emerged = obj.var[0] == 1;
if (emerged)
jjDrawSpriteFromCurFrame(obj.xPos, titsYPos + 5, obj.curFrame, 1, SPRITE::SHADOW,0, 4); //tits
jjDrawSpriteFromCurFrame(obj.xPos, titsYPos, obj.curFrame, 1, mode,0, emerged ? 3 : 5); //tits
if (summoningArms)
for (int half = 0; half < 2; ++half)
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos - 45, FirstTileFrameID + 2 + half, jjGameTicks << 1, 1,1, SPRITE::ALPHAMAP, 0, 3);
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
if (bullet is null) {
if (player.ballTime < 30) {
player.ballTime = 35;
player.xSpeed = (player.xPos - obj.xPos) / 7;
player.ySpeed = (player.yPos - obj.yPos) / 6;
player.buttstomp = 121;
obj.justHit = 8;
jjSample(obj.xPos, obj.yPos, SOUND::PICKUPS_BOING_CHECK);
}
} else {
if (obj.justHit == 0) {
if (obj.freeze != 0) {
obj.freeze = 0;
obj.unfreeze(1);
obj.state = obj.oldState;
force += 3;
} else {
if (jjIsTSF)
jjSample(obj.xPos, obj.yPos - 70, SOUND::Sample(SOUND::LORISOUNDS_HURT0 + (jjRandom() & 7)), 63, 25000);
else
jjSample(obj.xPos, obj.yPos - 70, SOUND::Sample(SOUND::JAZZSOUNDS_HEY1 + (jjRandom() & 3)), 63, 17500);
}
obj.justHit = 7;
obj.energy -= force;
obj.doesHurt = 6;
}
bullet.state = STATE::EXPLODE; //no fireballs in level
}
return true;
}
}
void BossBat(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.direction = obj.creatorID - 1;
obj.determineCurAnim(ANIM::BAT, 0);
obj.state = STATE::WAKE;
//obj.points = 0;
} if (obj.state == STATE::WAKE) {
if (++obj.counter < 200) {
obj.xPos += obj.direction;
obj.yPos -= 2.5;
obj.frameID = obj.counter >> 3;
obj.determineCurFrame();
} else
obj.state = STATE::FLY;
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::SINGLECOLOR, 0, 3);
} else {
obj.xOrg = jjPlayers[obj.var[0]].xPos;
obj.yOrg = jjPlayers[obj.var[0]].yPos;
obj.behave(jjObjectPresets[OBJECT::BAT].behavior);
}
}
void BossChoker(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.energy = 0;
obj.bulletHandling = HANDLING::DESTROYBULLET;
obj.isFreezable = true; //this is fine
obj.isBlastable = false;
obj.state = STATE::FALL;
obj.ySpeed = 3 + jjDifficulty;
obj.curFrame = jjAnimations[obj.curAnim];
} else if (obj.freeze != 0) {
if (--obj.freeze == 0) {
obj.unfreeze(0);
obj.state = obj.oldState;
}
} else if (++obj.age >= 200) {
obj.deactivate();
} else
obj.yPos += obj.ySpeed;
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -(obj.objectID + obj.age) << 3, 1,1, obj.freeze == 0 ? SPRITE::NORMAL : SPRITE::FROZEN, 0, 3);
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame - 1, 1, obj.freeze == 0 ? SPRITE::NORMAL : SPRITE::FROZEN, 0, 3);
}
///@Event 211=Force Wheel |-|Platform |Force |Wheel |Sync:2|Speed:-6|Length:4|Swing:{Circle,Pendulum}1|Angle:{R,D,UR,DR}2
void ForceWheel(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.xAcc = obj.xOrg;
obj.yAcc = obj.yOrg;
const int angle = jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 13, 2);
if (angle != 1)
obj.var[9] = 1;
if (angle == 2)
obj.var[10] = -1;
else if (angle & 1 == 1)
obj.var[10] = 1;
obj.doesHurt = jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0, 2);
} else if (obj.state == STATE::DEACTIVATE) {
if (obj.xAcc != 0 && obj.yAcc != 0) {
obj.xOrg = obj.xAcc;
obj.yOrg = obj.yAcc;
}
}
obj.behave(BEHAVIOR::PLATFORM);
bool stoodOn = false;
for (int i = 0; i < jjLocalPlayerCount; ++i) {
const jjPLAYER@ play = jjLocalPlayers[i];
if (play.platform == obj.objectID) {
stoodOn = true;
if (play.spriteMode == SPRITE::INVISIBLE && (play.blink == 0 || (jjRenderFrame & 4) == 4))
jjDrawSprite(play.xPos, play.yPos, play.setID, play.keyRun ? RABBIT::RUN3 : RABBIT::RUN1, jjGameTicks >> 2, play.direction, SPRITE::PLAYER, play.playerID, 3);
}
}
if (!stoodOn && obj.doesHurt != 0) {
if (obj.xOrg > obj.xAcc + 0.5) obj.xOrg -= 1;
else if (obj.xOrg < obj.xAcc - 0.5) obj.xOrg += 1;
if (obj.yOrg > obj.yAcc + 0.5) obj.yOrg -= 1;
else if (obj.yOrg < obj.yAcc - 0.5) obj.yOrg += 1;
}
}
void onPlayer(jjPLAYER@ play) {
if (ImmobilizePlayers) {
//play.spriteMode = SPRITE::INVISIBLE;
play.keyFire = play.keyJump = play.keyRun = play.keySelect = play.keyLeft = play.keyRight = play.keyUp = play.keyDown = false;
play.xSpeed = 0;
play.invincibility = -2;
return;
} //else play.spriteMode = SPRITE::PLAYER;
jjOBJ@ obj = jjObjects[play.platform];
if (obj.behavior == ForceWheel) {
int negacc;
if (obj.counter>256*511) {
negacc=obj.counter/256-1024;
} else {
negacc=obj.counter/256;
}
if ((obj.var[3]>32) && (negacc>0)) {
negacc+=32;
} else if ((obj.var[3]<-32) && (negacc<0)) {
negacc-=32;
}
const int maxChange = int(abs(negacc)) + 34;
play.spriteMode = SPRITE::INVISIBLE;
play.idle = 0;
if (play.keyRight) {
obj.var[3] = obj.var[3] + maxChange;
if (play.direction == 1)
play.keyRight = false;
} else if (play.keyLeft) {
obj.var[3] = obj.var[3] - maxChange;
if (play.direction == -1)
play.keyLeft = false;
} else
play.spriteMode = SPRITE::PLAYER;
obj.var[8] = obj.var[8] + maxChange - 34;
while (obj.var[8] >= 256) {
obj.var[8] = obj.var[8] - 256;
const int
xTarget = int(obj.xOrg) + play.direction * obj.var[9],
yTarget = int(obj.yOrg) + play.direction * obj.var[10];
if (!jjMaskedPixel(xTarget, yTarget) && jjEventGet(xTarget>>5, yTarget>>5) != AREA::STOPENEMY) {
obj.xOrg = xTarget;
obj.yOrg = yTarget;
}
}
play.xSpeed = 0;
} else
play.spriteMode = SPRITE::PLAYER;
if (play.boss != 0 && jjSubscreenHeight >= 320)
play.cameraFreeze(387*32 + 16, 360, true, true);
else
play.cameraUnfreeze();
}
void Platform3D(jjOBJ@ obj) {
if (obj.state == STATE::START && jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 1, 1) == 1)
obj.special = 512;
obj.behave(BEHAVIOR::SPIKEBOLL3D);
if (obj.curFrame != 0 && obj.state != STATE::DEACTIVATE) {
obj.bePlatform(obj.xPos, obj.yPos);
if (obj.counterEnd < 50) {
++obj.counterEnd;
--obj.counter;
obj.var[4] = obj.special - obj.var[5];
}
} else {
obj.clearPlatform();
if (obj.counterEnd != 0) {
obj.counterEnd = 0;
obj.special = obj.special ^ 512;
}
}
}
bool ImmobilizePlayers = false;
class TileFragment {
uint16 tileID;
uint8 quadrant;
int xOrg, yOrg, angle;
TileFragment(){}
TileFragment(uint16 i, uint8 q, int x, int y, int a){ tileID = i; quadrant = q; xOrg = x; yOrg = y; angle = a; }
}
array<TileFragment> TileFragments;
void GatherTileFragments() {
const int screenWidthTiles = (jjSubscreenWidth + 31) >> 5;
const int screenHeightTiles = (jjSubscreenHeight + 31) >> 5;
for (int i = 0; i < jjLocalPlayerCount; ++i) {
const jjPLAYER@ play = jjLocalPlayers[i];
const int cameraX = int(play.cameraX), cameraY = int(play.cameraY);
for (int layerID = 6; layerID >= 3; --layerID) {
const jjLAYER@ layer = jjLayers[layerID];
int layerCameraX, layerCameraY;
if (layerID != 6) {
layerCameraX = cameraX & ~31;
layerCameraY = cameraY & ~31;
} else {
layerCameraX = int(layer.getXPosition(play));
layerCameraY = int(layer.getYPosition(play));
}
const int layerXOrg = layerCameraX >> 5, layerYOrg = layerCameraY >> 5;
if (layerID == 6) {
layerCameraX = cameraX - ((layerCameraX & 31));
layerCameraY = cameraY - ((layerCameraY & 31));
}
for (int x = 0; x <= screenWidthTiles; ++x)
for (int y = 0; y <= screenHeightTiles; ++y) {
const uint16 tileID = jjTileGet(layerID, layerXOrg + x, layerYOrg + y);
if (tileID != 0)
for (int q = 0; q < 4; ++q)
TileFragments.insertLast(TileFragment(tileID, q, layerCameraX + (x << 5) + ((q & 1) << 4), layerCameraY + (y << 5) + ((q & 2) << 3), jjRandom()));
}
}
}
}
void Teleportal(jjOBJ@ obj) {
if (obj.counter == 0) {
ImmobilizePlayers = true;
GatherTileFragments();
for (int layerID = 6; layerID >= 3; --layerID)
jjLayerHasTiles[layerID] = false;
//jjLayers[6].spriteMode = SPRITE::BLEND_NORMAL;
jjSamplePriority(SOUND::COMMON_TELPORT1);
} else if (obj.counter == 256) {
const uint8 warpID = jjParameterGet(uint(obj.xOrg) >> 5, (uint(obj.yOrg) >> 5) - 1, 0, 8);
jjSetLayerXSpeed(7, 0, false);
jjSetLayerXSpeed(8, 0, false);
jjSetLayerYSpeed(8, 0, false);
for (int i = 0; i < jjLocalPlayerCount; ++i)
jjLocalPlayers[i].warpToID(warpID, true);
jjSetLayerXSpeed(7, 0.1963043, false);
jjSetLayerXSpeed(8, 0.6, false);
jjSetLayerYSpeed(8, 0.6, false);
TileFragments.resize(0);
} else if (obj.counter == 258) {
GatherTileFragments();
} else if (obj.counter >= 516) {
for (int layerID = 6; layerID >= 3; --layerID)
jjLayerHasTiles[layerID] = true;
//jjLayers[6].spriteMode = SPRITE::NORMAL;
ImmobilizePlayers = false;
TileFragments.resize(0);
jjSamplePriority(SOUND::COMMON_TELPORT2);
obj.delete();
} else {
const int radius = ((obj.counter < 256) ? obj.counter * 4 : (obj.counter < 510) ? (510 - obj.counter) * 4 : (517 - obj.counter) / 2);
//jjLayers[6].spriteParam = (radius / 4 < 256) ? (255 - radius / 4) : 0;
for (uint i = 0; i < TileFragments.length; ++i) {
TileFragment@ fragment = TileFragments[i];
fragment.angle += 4;
jjDrawTile(fragment.xOrg + jjSin(fragment.angle) * radius, fragment.yOrg + jjCos(fragment.angle) * radius, fragment.tileID, TILE::Quadrant(fragment.quadrant));
}
}
obj.counter += (obj.counter < 500) ? 2 : 1;
}
void onFunction0(jjPLAYER@ play, bool left) {
if (abs(play.xSpeed) > 3 && ((play.xSpeed < 0) == left))
play.ySpeed = 5;
}
void onFunction1(jjPLAYER@ play) {
if (!play.bossActivated) {
play.activateBoss();
if (jjMusicLoad("beyond_-_creepy.it", true))
jjSetModSpeed(DesiredModSpeed = 6);
}
}
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.