Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Miscellaneous stuff | Violet CLM | Multiple | N/A |
const array<int> TurtleSpriteRecolorOffsets = {6*8, 5*8, 4*8, -2*8};
void onLevelLoad() {
for (uint i = 0; i < 4; ++i) {
jjANIMSET@ animSet = jjAnimSets[ANIM::CUSTOM[i]].load(ANIM::TUFBOSS);
for (uint j = 0; j < 6; ++j) { //animCount
jjANIMATION@ animation = jjAnimations[animSet.firstAnim + j];
for (uint k = 0; k < animation.frameCount; ++k) {
jjANIMFRAME@ frame = jjAnimFrames[animation.firstFrame + k];
jjPIXELMAP image(frame);
for (uint x = 0; x < image.width; ++x)
for (uint y = 0; y < image.height; ++y)
if (image[x,y] / 8 == 9) //gray
image[x,y] -= TurtleSpriteRecolorOffsets[i];
image.save(frame);
}
}
}
if (jjAnimSets[ANIM::TURTLE] == 0)
jjAnimSets[ANIM::TURTLE].load(); //want the sounds
for (uint xTile = 6; xTile < 9; ++xTile)
for (uint yTile = 6; yTile < 8; ++yTile) {
jjPIXELMAP oldTile(xTile + yTile*10);
jjPIXELMAP newTile();
for (uint xx = 0; xx < 32; ++xx)
for (uint yy = 0; yy < 32; ++yy)
newTile[31-yy, xx] = oldTile[xx,yy];
newTile.save(xTile + yTile*10, true); //rotated!
}
jjObjectPresets[OBJECT::GEMBARREL].behavior = Turtle;
jjObjectPresets[OBJECT::GEMBARREL].energy = 100; //maybe
jjObjectPresets[OBJECT::GEMBARREL].scriptedCollisions = true;
jjObjectPresets[OBJECT::GEMBARREL].playerHandling = HANDLING::SPECIAL;
jjObjectPresets[OBJECT::GEMBARREL].bulletHandling = HANDLING::DETECTBULLET;
jjObjectPresets[OBJECT::GEMBARREL].animSpeed = 9;
jjObjectPresets[OBJECT::GEMBARREL].age = 10; //damage that can be taken (in midair) before turning into a shell again
jjObjectPresets[OBJECT::GEMBARREL].special = 0; //no initial platform
jjObjectPresets[OBJECT::GEMBARREL].points = 0;
jjObjectPresets[OBJECT::ELECTROBULLET].behavior = Flailerang;
jjObjectPresets[OBJECT::ELECTROBULLET].killAnim = jjAnimSets[ANIM::AMMO].firstAnim + 6;
jjObjectPresets[OBJECT::BLASTERBULLET].animSpeed = 2; //to give physical attacks less of an advantage
jjObjectPresets[OBJECT::CAKE].behavior = BossHealthMeter;
jjObjectPresets[OBJECT::CAKE].playerHandling = HANDLING::PARTICLE; //just to be safe
jjObjectPresets[OBJECT::CAKE].energy = jjObjectPresets[OBJECT::GEMBARREL].energy;
jjObjectPresets[OBJECT::STEADYLIGHT].behavior = CenterOfLevel;
jjObjectPresets[OBJECT::BANANA].behavior = TurtleWood;
jjObjectPresets[OBJECT::BANANA].playerHandling = HANDLING::PARTICLE;
jjObjectPresets[OBJECT::BANANA].counterEnd = 96; //how long it has to rise
jjObjectPresets[OBJECT::BANANA].var[0] = 512; //initial angle
jjPIXELMAP WoodTiles(9, 0, 15, 96, 5);
jjPIXELMAP WoodSprite(96, 15);
jjANIMFRAME@ WoodFrame = jjAnimFrames[jjObjectPresets[OBJECT::BANANA].curFrame];
for (uint xx = 0; xx < 15; ++xx)
for (uint yy = 0; yy < 96; ++yy)
WoodSprite[95-yy, xx] = WoodTiles[xx,yy];
WoodSprite.save(WoodFrame);
WoodFrame.hotSpotX = -48;
WoodFrame.hotSpotY = -2;
jjObjectPresets[OBJECT::APPLE].behavior = BEHAVIOR::INACTIVE;
//jjObjectPresets[OBJECT::APPLE].playerHandling = HANDLING::PARTICLE;
//jjObjectPresets[OBJECT::APPLE].curFrame = jjObjectPresets[OBJECT::BANANA].curFrame;
jjObjectPresets[OBJECT::GEMBARREL].deactivates = false;
jjObjectPresets[OBJECT::BANANA].deactivates = false;
jjObjectPresets[OBJECT::APPLE].deactivates = false;
jjWeapons[WEAPON::GUN9].infinite = true;
jjWeapons[WEAPON::GUN9].defaultSample = false;
jjWeapons[WEAPON::GUN9].style = WEAPON::CAPPED;
jjAnimations[jjAnimSets[ANIM::PICKUPS] + 41] = jjAnimations[jjAnimSets[ANIM::PICKUPS] + 77];//pizza
jjWaterLayer = 6;
}
uint TurtlesDefeated = 0;
void onLevelReload() {
TurtlesDefeated = 0;
}
bool onDrawScore(jjPLAYER@ play, jjCANVAS@ screen) {
screen.drawString(0x8000, 30, "" + TurtlesDefeated + "/4", STRING::MEDIUM);
return true;
}
bool onDrawAmmo(jjPLAYER@ play, jjCANVAS@ screen) { return true; }
void onPlayerInput(jjPLAYER@ play) {
play.currWeapon = (play.platform == 0) ? WEAPON::BLASTER : WEAPON::GUN9;
}
void onDrawLayer6(jjPLAYER@ play, jjCANVAS@ screen) {
jjSetWaterLevel(-32, true);
}
void onDrawLayer4(jjPLAYER@ play, jjCANVAS@ screen) {
jjSetWaterLevel(16000, true);
}
enum TurtleAnims { taTHROW, taCATCH, taSHELL, taFLAILERANG, taSTAND, taWALK };
void startAnimation(jjOBJ@ obj, TurtleAnims animID, bool onGround) {
obj.determineCurAnim(ANIM::CUSTOM[obj.doesHurt], animID);
obj.frameID = 0;
obj.determineCurFrame();
obj.counterEnd = obj.animSpeed;
if (onGround) {
obj.yPos -= 50; //some room to fall
obj.putOnGround(true);
}
}
void Turtle(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.doesHurt = jjParameterGet(int(obj.xOrg / 32), int(obj.yOrg / 32), 0, 3); //color
@Turtles[obj.doesHurt] = obj;
obj.state = STATE::DELAYEDSTART;
obj.counter = jjParameterGet(int(obj.xOrg / 32), int(obj.yOrg / 32), 4, 4) * 70; //delay
startAnimation(obj, taSHELL, true);
} else if (obj.age <= 0) { //sustained too much damage
obj.age = jjObjectPresets[obj.eventID].age;
obj.state = STATE::TURN;
obj.ySpeed = -4;
jjSample(obj.xPos, obj.yPos, SOUND::TURTLE_TURN);
startAnimation(obj, taSHELL, false);
obj.xSpeed = -5 * obj.direction;
deleteWood(obj);
}
if (obj.state == STATE::DELAYEDSTART) {
if (abs(obj.xSpeed) > 0.2f) {
if (!jjMaskedPixel(int(obj.xPos + obj.xSpeed), int(obj.yPos))) //can move
obj.xPos += obj.xSpeed;
else {
obj.xSpeed = -obj.xSpeed;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_IMPACT7);
}
if (obj.xSpeed > 0) {
obj.xSpeed -= 0.1f;
obj.direction = 1;
} else {
obj.xSpeed += 0.1f;
obj.direction = -1;
}
}
if (--obj.counter <= 0) {
jjSample(obj.xPos, obj.yPos, SOUND::TURTLE_HIDE);
obj.state = STATE::WAIT;
obj.counter = 100;
startAnimation(obj, taSTAND, true);
obj.direction = (obj.xPos > CENTERX) ? -1 : 1;
}
} else if (obj.state == STATE::WAIT) {
if (--obj.counter <= 0) {
obj.state = STATE::WALK;
startAnimation(obj, taWALK, true);
}
} else if (obj.state == STATE::WALK) {
if (abs(obj.xPos - CENTERX) > 3) { //not at center
if (obj.xPos > CENTERX)
obj.xPos -= 1.4f;
else
obj.xPos += 1.4f;
} else {
obj.special = jjAddObject(OBJECT::BANANA, CENTERX, jjLayerHeight[4] * 32); //flying platform
jjObjects[obj.special].special = obj.objectID; //mutual
obj.state = STATE::JUMP;
obj.counter = 200 + (obj.doesHurt * 50);
startAnimation(obj, taSTAND, true);
obj.direction = (obj.xPos > jjLocalPlayers[0].xPos) ? -1 : 1;
}
} else if (obj.state == STATE::JUMP) {
if (--obj.counter <= 0) {
obj.state = STATE::FIRE;
startAnimation(obj, taTHROW, false);
}
} else if (obj.state == STATE::FIRE) {
if (obj.frameID == 13 && obj.counterEnd == uint(obj.animSpeed)) {
obj.fireBullet(OBJECT::ELECTROBULLET);
} else if (obj.frameID == 18 && obj.counterEnd == 1) {
obj.state = STATE::JUMP;
obj.counter = 200 + (obj.doesHurt * 50);
startAnimation(obj, taSTAND, false);
} else
obj.var[2] = jjSampleLooped(obj.xPos, obj.yPos, SOUND::TUFBOSS_SWING, obj.var[2]);
} else if (obj.state == STATE::TURN) {
obj.xPos += obj.xSpeed;
obj.yPos += obj.ySpeed;
/*if (obj.xSpeed > 0) {
obj.xSpeed -= 0.1f;
obj.direction = 1;
} else {
obj.xSpeed += 0.1f;
obj.direction = -1;
}*/
obj.ySpeed += 0.2f;
if (obj.xPos < 60) {
obj.xPos = 60;
obj.xSpeed = abs(obj.xSpeed);
obj.direction = 1;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_IMPACT7);
} else if (obj.xPos > jjLayerWidth[4] * 32 - 60) {
obj.xPos = jjLayerWidth[4] * 32 - 60;
obj.xSpeed = -abs(obj.xSpeed);
obj.direction = -1;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_IMPACT7);
}
if (obj.yPos > 23*32) {
obj.state = STATE::DELAYEDSTART;
obj.counter = 140; //delay
startAnimation(obj, taSHELL, true);
}
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, jjGameTicks * -16 * obj.direction, obj.direction);
return;
}
if (--obj.counterEnd == 0) {
obj.counterEnd = obj.animSpeed;
++obj.frameID;
obj.frameID %= jjAnimations[obj.curAnim].frameCount;
obj.determineCurFrame();
}
if (!(obj.special != 0 && jjObjects[obj.special].counterEnd == 0)) //wooden platform has finished ascending and has taken over
obj.draw();
}
void onObjectHit(jjOBJ@ obj, jjOBJ@ bull, jjPLAYER@ play, int force) {
if (obj.behavior == Turtle) {
if (bull is null) {
if (obj.state == STATE::DELAYEDSTART) //in shell
play.hurt();
else if (obj.state != STATE::TURN) {
int oldEnergy = obj.energy;
play.objectHit(obj, play.getObjectHitForce(obj), HANDLING::ENEMY);
if (obj.special != 0)
obj.age -= (oldEnergy - obj.energy);
}
} else {
if (obj.state != STATE::DELAYEDSTART && obj.state != STATE::TURN) {
obj.energy -= force;
if (obj.special != 0) {
if (bull.behavior == Flailerang) //instant defeat!
obj.age = 0;
else obj.age -= 1; //incremental
}
obj.justHit = 5;
jjSample(obj.xPos, obj.yPos, SOUND::TURTLE_IDLE2);
bull.state = STATE::EXPLODE;
} else {
jjSample(obj.xPos, obj.yPos, SOUND::TURTLE_HITSHELL);
obj.xSpeed = bull.xSpeed;
obj.counter += 30; //stay in shell longer
if (!bull.ricochet()) //surely always true
bull.state = STATE::EXPLODE;
}
}
if (obj.energy <= 0) { //still exist, so the energy can be counted, but don't interact with anything
obj.energy = 0; //to avoid triggering level end too quickly
obj.bulletHandling = HANDLING::IGNOREBULLET;
obj.behavior = BEHAVIOR::BEES; //do nothing
obj.particlePixelExplosion((bull is null) ? 2 : 0);
++TurtlesDefeated;
deleteWood(obj);
}
}
}
void deleteWood(jjOBJ@ obj) {
if (obj.special != 0) {
jjOBJ@ wood = jjObjects[obj.special];
wood.special = 0;
obj.special = 0;
wood.behavior = RabbitWood;
}
}
array<jjOBJ@> Turtles(4);
void BossHealthMeter(jjOBJ@ obj) {
if (obj.state == STATE::START) {
jjLocalPlayers[0].activateBoss();
jjLocalPlayers[0].boss = obj.objectID;
obj.state = STATE::WAIT;
}
int combinedEnergy = Turtles[0].energy + Turtles[1].energy + Turtles[2].energy + Turtles[3].energy;
if (combinedEnergy <= 0) {
jjLocalPlayers[0].activateBoss(false);
jjNxt("BossrushV2");
obj.delete(); //don't try to cycle more than once
} else
obj.energy = combinedEnergy / 4; //for display
}
float CENTERX;
void CenterOfLevel(jjOBJ@ obj) {
CENTERX = obj.xOrg;
obj.behavior = BEHAVIOR::STEADYLIGHT;
}
void orientWoodToward(jjOBJ@ obj, int targetAngle, int turnSpeed, float platSpeed) {
int currentAngle = obj.var[0];
if (currentAngle != targetAngle) {
float angleDifference = abs(((currentAngle + 512 - targetAngle) & 1023) - 512);
if (angleDifference > 512) angleDifference = abs(angleDifference - 1024);
if (int(currentAngle + angleDifference) & 1023 == targetAngle)
currentAngle += turnSpeed;
else
currentAngle -= turnSpeed;
currentAngle &= 1023;
}
obj.xSpeed = jjSin(currentAngle) * platSpeed;
obj.ySpeed = jjCos(currentAngle) * platSpeed;
obj.var[0] = currentAngle;
obj.var[1] = targetAngle;
float oldX = obj.xPos, oldY = obj.yPos;
obj.xPos += obj.xSpeed;
obj.yPos += obj.ySpeed;
obj.bePlatform(oldX, oldY);
}
void TurtleWood(jjOBJ@ obj) {
jjOBJ@ turtle = jjObjects[obj.special];
if (obj.counterEnd > 0) {
obj.yPos -= 2;
obj.counterEnd -= 2;
if (obj.counterEnd == 0) {
}
obj.draw();
} else {
jjPLAYER@ target = jjLocalPlayers[0];
const int targetAngle = int(atan2(target.xPos - obj.xPos, target.yPos - obj.yPos) / 6.28f * 1024) & 1023;
orientWoodToward(obj, targetAngle, turtle.doesHurt + 2, 4);
turtle.xPos = obj.xPos;
turtle.yPos = obj.yPos - 25;
turtle.direction = (obj.xSpeed >= 0) ? 1 : -1;
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, int(obj.xSpeed) * 8);
jjDrawRotatedSpriteFromCurFrame(turtle.xPos, turtle.yPos, turtle.curFrame, int(obj.xSpeed) * 8, turtle.direction, 1, (turtle.justHit == 0) ? SPRITE::NORMAL : SPRITE::SINGLECOLOR, 15);
}
}
void RabbitWood(jjOBJ@ obj) {
if (obj.counterEnd > 0) {
obj.yPos -= 2;
obj.counterEnd -= 2;
if (obj.counterEnd == 0) {
}
obj.draw();
} else {
jjPLAYER@ play = jjLocalPlayers[0];
if (play.platform != obj.objectID) {
/*obj.particlePixelExplosion(0);
obj.clearPlatform();
obj.delete();
jjSamplePriority(SOUND::COMMON_COLLAPS);*/
obj.var[0] = 512; //angle=up
const float oldY = obj.yPos;
obj.yPos = oldY + 2;
obj.xSpeed = jjSin(jjGameTicks * 16) * 3;
if (play.platform == 0)
obj.bePlatform(obj.xPos, oldY);
} else {
int targetAngle = 256;
if (play.keyUp) targetAngle = 512;
else if (play.keyDown) targetAngle = 0;
else if (play.direction < 0) targetAngle = 768;
orientWoodToward(obj, targetAngle, (play.keyRun ? 10 : 5), (play.keyRun ? 5.5 : 4));
}
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, int(obj.xSpeed) * 8);
}
}
void onFunction0(jjPLAYER@ play) {
jjObjects[jjAddObject(OBJECT::BANANA, CENTERX, jjLayerHeight[4] * 32, play.playerID, CREATOR::PLAYER, RabbitWood)].counterEnd -= 2; //flying platform
}
/*void YourWood(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.counter = jjParameterGet(int(obj.xOrg / 32), int(obj.yOrg / 32), 0, 8) * 4;
}
float oldY = obj.yPos;
obj.yPos = obj.yOrg + jjSin(jjGameTicks * 2 + obj.counter) * 96;
obj.bePlatform(obj.xPos, oldY);
obj.draw();
}*/
void Flailerang(jjOBJ@ obj) {
if (obj.state == STATE::DEACTIVATE) {
obj.delete();
return;
} else if (obj.state == STATE::START) {
jjSample(obj.xPos, obj.yPos, SOUND::TUFBOSS_RELEASE);
obj.state = STATE::FLY;
int angle;
if (obj.creatorType == CREATOR::OBJECT) {
jjOBJ@ turtle = jjObjects[obj.creator];
angle = jjObjects[turtle.special].var[1];
obj.determineCurAnim(ANIM::CUSTOM[turtle.doesHurt], taFLAILERANG);
obj.playerHandling = HANDLING::ENEMYBULLET;
} else {
angle = jjObjects[jjPlayers[obj.creator].platform].var[1];
obj.determineCurAnim(ANIM::CUSTOM[0], taFLAILERANG);
obj.animSpeed = 7; //do more damage than the blaster
}
obj.xSpeed = jjSin(angle) * 5;
obj.ySpeed = jjCos(angle) * 5;
obj.direction = (obj.xSpeed > 0) ? 1 : -1;
} else if (obj.state == STATE::EXPLODE) {
if (obj.creator == CREATOR::PLAYER)
obj.particlePixelExplosion(16);
obj.behavior = BEHAVIOR::EXPLOSION;
obj.curAnim = obj.killAnim;
obj.playerHandling = HANDLING::EXPLOSION;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_METALHIT);
return;
}
obj.xPos += obj.xSpeed;
obj.yPos += obj.ySpeed;
obj.frameID = (jjGameTicks >> 2) % jjAnimations[obj.curAnim].frameCount;
obj.determineCurFrame();
if (obj.creatorType == CREATOR::OBJECT)
obj.draw();
else
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, -8); //green
}
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.