Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Jazz of the Jungle | Violet CLM | Single player | 8.9 |
const bool MLLESetupSuccessful = MLLE::Setup(); ///@MLLE-Generated
#include "MLLE-Include-1.5.asc" ///@MLLE-Generated
#pragma require "Aztec2.j2t" ///@MLLE-Generated
#pragma require "Amazont.j2t" ///@MLLE-Generated
#pragma require "Jazz-otJ.j2as" ///@MLLE-Generated
#include "Jazz1Enemies v05.asc"
#pragma require "FishFace.j2a"
#pragma require "JillYEAH.wav"
#include "ArtificialArrow.asc"
class PlayerX {
PlayerX(){}
bool Fish = false;
bool Immobile = false;
int NoJumping = 0;
float WaterLevel = jjLayerHeight[4] * 32;
int Apples = 2;
}
array<PlayerX> PlayersX(jjLocalPlayerCount);
const int KeyCurFrame = jjObjectPresets[147].curFrame;
void onLevelLoad() {
///@Event 142=Bouncing Ball |-|Enemy |Bounce|Ball
Jazz1::MakeEnemy(142, Jazz1::Enemies::Battleships_BounceSpike).SetUsesJJ2StyleDeathAnimation(true).SetPointsFormula(Jazz1::PointsFormula::MultiplyByFive).SetDeathSound(SOUND::COMMON_METALHIT);
///@Event 143=Flying Devil |-|Enemy |Devil|Fly
Recolor(Jazz1::MakeEnemy(143, Jazz1::Enemies::Holidaius_Devil).SetUsesJJ2StyleDeathAnimation(true).SetPointsFormula(Jazz1::PointsFormula::MultiplyByFive).SetDeathSound(SOUND::BUBBA_BUBBAEXPLO).GetFirstFrame(), 2, array<uint8> = {40,24, 56,24});
///@Event 144=Snake |-|Enemy |Snake
Recolor(Jazz1::MakeEnemy(144, Jazz1::Enemies::Jungrock_JetSnake).SetUsesJJ2StyleDeathAnimation(true).SetPointsFormula(Jazz1::PointsFormula::MultiplyByFive).GetFirstFrame(), 3, array<uint8> = {56,79});
///@Event 145=Slug |-|Enemy |Slug
Recolor(Jazz1::MakeEnemy(145, Jazz1::Enemies::Sluggion_Sluggi, false, 2, Resize::Method::Scale2x).SetUsesJJ2StyleDeathAnimation(true).SetPointsFormula(Jazz1::PointsFormula::MultiplyByFive).SetWalkingEnemyCliffReaction(Jazz1::CliffReaction::TurnAround).SetSpeed(0.4).SetDeathSound(SOUND::HATTER_SPLIN).GetFirstFrame(), 3, array<uint8> = {16,72, 56,72, 40,75, 24,32});
DeactivateEnemyWrappers(array<uint8>={142,143,144,145});
//if (jjAnimSets[ANIM::PLUS_SCENERY] == 0)
// jjAnimSets[ANIM::PLUS_SCENERY].load();
///@Event 237=Beehive |-|Enemy |Hive
jjObjectPresets[OBJECT::BEEBOY].behavior = OhBeehive;
///@Event 253=Pacman Ghost |-|Enemy |Pacman|Ghost|Bird:c1
jjObjectPresets[OBJECT::PACMANGHOST].behavior = PacmanGhost();
jjObjectPresets[OBJECT::PACMANGHOST].scriptedCollisions = true;
jjObjectPresets[OBJECT::PACMANGHOST].playerHandling = HANDLING::SPECIAL;
jjObjectPresets[OBJECT::PACMANGHOST].bulletHandling = HANDLING::DETECTBULLET;
jjObjectPresets[OBJECT::BLASTERBULLET].determineCurAnim(ANIM::AMMO, 49);
jjObjectPresets[OBJECT::BLASTERBULLET].special = 0;
jjObjectPresets[OBJECT::BLASTERBULLET].behavior = WeaponOne;
jjWeapons[WEAPON::BLASTER].defaultSample = false;
jjWeapons[WEAPON::BLASTER].replenishes = false;
jjObjectPresets[OBJECT::BOUNCERBULLET].behavior = SpikeBall;
jjObjectPresets[OBJECT::BOUNCERBULLET].determineCurAnim(ANIM::ROBOT, 0);
jjObjectPresets[OBJECT::BOUNCERBULLET].special = 0;
jjObjectPresets[OBJECT::BOUNCERBULLET].determineCurFrame();
jjObjectPresets[OBJECT::BOUNCERBULLET].var[0] = 26;
jjObjectPresets[OBJECT::BOUNCERBULLET].counterEnd /= 2;
jjObjectPresets[OBJECT::BOUNCERBULLET].animSpeed = 3;
jjWeapons[WEAPON::BOUNCER].defaultSample = false;
jjWeapons[WEAPON::BLASTER].style = WEAPON::CAPPED;
jjWeapons[WEAPON::BOUNCER].style = WEAPON::CAPPED;
Recolor(jjAnimations[jjAnimSets[ANIM::AMMO] + 66], 9, array<uint8>={64, 40});
Recolor(jjAnimations[jjAnimSets[ANIM::AMMO] + 49], 10, array<uint8>={16,24, 24,88});
if (jjAnimSets[ANIM::FISH] == 0)
jjAnimSets[ANIM::FISH].load();
jjAnimSets[ANIM::CUSTOM[0]].load(0, "FishFace.j2a");
for (uint i = 0; i < 2; ++i) {
jjANIMATION@ fishAnim = jjAnimations[jjAnimSets[ANIM::DOG] + i] = jjAnimations[jjAnimSets[ANIM::FISH] + i];
for (uint j = 0; j < fishAnim.frameCount; ++j) {
jjANIMFRAME@ fishFrame = jjAnimFrames[fishAnim + j];
fishFrame.coldSpotY = -fishFrame.height;
}
}
jjObjectPresets[OBJECT::DOGGYDOGG].determineCurFrame();
jjObjectPresets[OBJECT::DOGGYDOGG].behavior = function(o) { if (o.state == STATE::KILL) o.deactivate(); o.behave(BEHAVIOR::DOGGYDOGG); };
///@Event 146=Morph Head |-|Morph |Morph|Head|Character:{Rabbit,Frog,Bird,Fish}2|notcheckpoint:c1
jjObjectPresets[146].behavior = MorphHead();
jjObjectPresets[146].playerHandling = HANDLING::SPECIAL;
jjObjectPresets[146].scriptedCollisions = true;
for (int i = 0; i < 3; ++i) {
jjPIXELMAP key(611 - i * 90);
jjANIMFRAME@ frame = jjAnimFrames[KeyCurFrame - i];
key.save(frame);
frame.hotSpotX = frame.hotSpotY = -16;
}
///@Event 147=Key|_|Trigger |Key||Type:{Key,Gem}1
jjObjectPresets[147].behavior = Key();
jjObjectPresets[147].scriptedCollisions = true;
if (jjAnimSets[ANIM::DESTSCEN] == 0)
jjAnimSets[ANIM::DESTSCEN].load();
///@Event 154=Lock|_|Trigger |Lock||Type:{Key,Gem,Right,Left}2|Height-1:2
jjObjectPresets[154].behavior = Lock();
jjObjectPresets[154].scriptedCollisions = true;
jjAnimSets[ANIM::FENCER].allocate(array<uint>={0,0});;
jjAnimations[jjAnimSets[ANIM::FENCER] + 0] = jjAnimations[jjAnimSets[ANIM::FROG] + 0];
jjAnimations[jjAnimSets[ANIM::FENCER] + 1] = jjAnimations[jjAnimSets[ANIM::FROG] + 2];
///@Event 155=Frog|-|Enemy |Frog
jjObjectPresets[155].behavior = BEHAVIOR::FENCER;
jjObjectPresets[155].energy = 1;
jjObjectPresets[155].playerHandling = HANDLING::ENEMY;
jjObjectPresets[155].bulletHandling = HANDLING::HURTBYBULLET;
jjObjectPresets[155].points = jjObjectPresets[OBJECT::FENCER].points;
jjObjectPresets[155].determineCurAnim(ANIM::FENCER, 1);
jjObjectPresets[155].determineCurFrame();
jjObjectPresets[155].behavior = FrogFencer;
jjObjectPresets[OBJECT::APPLE].behavior = Apple();
jjObjectPresets[OBJECT::APPLE].scriptedCollisions = true;
jjObjectPresets[OBJECT::CARROT].behavior =
jjObjectPresets[OBJECT::FASTFIRE].behavior =
jjObjectPresets[OBJECT::REDGEM].behavior =
jjObjectPresets[OBJECT::GREENGEM].behavior =
jjObjectPresets[OBJECT::BLUEGEM].behavior =
BEHAVIOR::INACTIVE;
jjCharacters[CHAR::JAZZ].groundJump = GROUND::CROUCH;
jjCharacters[CHAR::SPAZ].groundJump = GROUND::CROUCH;
if (jjIsTSF)
jjCharacters[CHAR::LORI].groundJump = GROUND::CROUCH;
jjCharacters[CHAR::BIRD2].canRun = true;
jjCharacters[CHAR::SPAZ].airJump = AIR::HELICOPTER;
GenerateWaterLayer();
jjUseLayer8Speeds = true;
jjTexturedBGStyle = TEXTURE::WARPHORIZON;
jjTexturedBGUsed = true;
jjTexturedBGTexture = TEXTURE::RANEFORUSV;
jjSetFadeColors(166);
{
jjPIXELMAP vine(0,0,32,136);
for (uint x = 0; x < 32; ++x)
for (uint y = 0; y < 136; ++y)
if (vine[x,y] == 0)
vine[x,y] = 128;
jjANIMFRAME@ vineFrame = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::VINE]] + 1];
vine.save(vineFrame);
vineFrame.hotSpotX = -16;
}
///@Event 34=Ammo |-|Ammo |Ammo||Spike:c1
jjObjectPresets[OBJECT::BOUNCERAMMO3].behavior = Ammo();
jjObjectPresets[OBJECT::BOUNCERAMMO3].scriptedCollisions = true;
jjSampleLoad(SOUND::COMMON_COIN, "JillYEAH.wav");
onLevelReload();
for (int x = jjLayerWidth[3]; --x >= 0;)
for (int y = jjLayerHeight[3]; --y >= 0;) {
const uint8 ev = jjEventGet(x,y);
if (ev == AREA::WARPTARGET) {
const uint targetID = jjParameterGet(x,y,0,8);
if (targetID >= Targets.length)
Targets.resize(targetID + 1);
Targets[targetID] = array<int> = {x * 32 + 16, y * 32 + 16};
//jjEventSet(x,y, 0);
}
}
if (jjDifficulty > 0)
jjHelpStrings[5] = jjHelpStrings[5] + "@@You can hold TAB at any time@for a hint to your next goal.";
}
//enemies:
///@Event 100=
///@Event 102=
///@Event 103=
///@Event 104=
///@Event 105=
///@Event 106=
///@Event 107=
///@Event 108=
///@Event 109=
///@Event 110=
///@Event 113=
///@Event 115=
///@Event 117=
///@Event 118=
///@Event 120=
///@Event 123=
///@Event 124=
///@Event 125=
///@Event 126=
///@Event 127=
///@Event 152=
///@Event 183=
///@Event 184=
///@Event 190=
///@Event 191=
///@Event 197=
///@Event 225=
///@Event 236=
///@Event 237=
///@Event 248=
///@Event 249=
///@Event 250=
///@Event 252=
void Recolor(uint frameID, uint frameCount, array<uint8> gradients) {
while (frameCount-- != 0) {
jjANIMFRAME@ frame = jjAnimFrames[frameID++];
jjPIXELMAP image(frame);
for (uint x = 0; x < frame.width; ++x)
for (uint y = 0; y < frame.height; ++y)
for (uint g = 0; g < gradients.length; g += 2)
if (image[x,y] & ~7 == gradients[g]) {
const uint8 replacement = gradients[g+1];
//if (replacement < 112)
image[x,y] = (image[x,y] & 7) + replacement;
//else
// image[x,y] = ((image[x,y] & 7) << 1) + replacement;
break;
}
image.save(frame);
}
}
class DeactivateEnemyWrapper : jjBEHAVIORINTERFACE {
Jazz1::Enemy@ enemy;
DeactivateEnemyWrapper(Jazz1::Enemy@ e) { @enemy = @e; }
void onBehave(jjOBJ@ obj) {
enemy.onBehave(obj);
if (obj.state == STATE::KILL && obj.creatorType == CREATOR::LEVEL) {
//jjEventSet(int(obj.xOrg)/32, int(obj.yOrg)/32, obj.eventID); //shouldn't be needed
jjParameterSet(int(obj.xOrg)/32, int(obj.yOrg)/32, -1, 1, 0); //deactivate
}
}
void onDraw(jjOBJ@ obj) { enemy.onDraw(obj); }
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) { return enemy.onObjectHit(obj, bullet, player, force); }
}
void DeactivateEnemyWrappers(array<uint8> objectIDs) {
for (uint i = 0; i < objectIDs.length; ++i)
jjObjectPresets[objectIDs[i]].behavior = DeactivateEnemyWrapper(cast<Jazz1::Enemy@>(cast<jjBEHAVIORINTERFACE>(jjObjectPresets[objectIDs[i]].behavior)));
}
void OhBeehive(jjOBJ@ obj) {
if (obj.creatorType == CREATOR::LEVEL) {
if (obj.state == STATE::START) {
obj.determineCurAnim(ANIM::PLUS_SCENERY, 3);
obj.state = STATE::STILL;
obj.counterEnd = 0;
obj.energy = 5;
} else {
if (obj.state == STATE::KILL)
jjParameterSet(int(obj.xOrg)/32, int(obj.yOrg)/32, -1, 1, 0); //deactivate
obj.behave(BEHAVIOR::FISH);
if (obj.counterEnd != 0) {
if (obj.counterEnd == 255) {
jjOBJ@ lastBee = jjObjects[obj.special];
if (lastBee.behavior != OhBeehive || lastBee.creatorID != uint(obj.objectID) || lastBee.state != STATE::IDLE) {
obj.counterEnd = 0; //will be changed to 1 momentarily
obj.special = jjAddObject(obj.eventID, obj.xPos, obj.yPos, obj.objectID, CREATOR::OBJECT);
} else { //already got one buzzing around
obj.counterEnd = 220; //check again soon
}
}
++obj.counterEnd;
} else if (obj.findNearestPlayer(200*200) >= 0)
obj.counterEnd = 192;
}
} else {
if (obj.state == STATE::ATTACK) {
jjDifficulty -= 1;
obj.counter = 70; //never stop
obj.behave(BEHAVIOR::BEE);
jjDifficulty += 1;
} else
obj.behave(BEHAVIOR::BEE);
}
}
bool everyOtherBirdShot = false;
void WeaponOne(jjOBJ@ obj) {
const jjPLAYER@ player = jjPlayers[obj.creatorID];
if (player.charCurr == CHAR::BIRD2) {
everyOtherBirdShot = !everyOtherBirdShot;
if (everyOtherBirdShot) {
obj.delete();
return;
}
obj.special = obj.determineCurAnim(ANIM::AMMO, 66);
obj.behavior = BirdShot;
obj.animSpeed = 2;
obj.var[3] = 5; //not blaster
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_FLAP);
} else if (PlayersX[player.localPlayerID].Fish) {
obj.determineCurAnim(ANIM::AMMO, 30);
obj.behavior = BEHAVIOR::BULLET;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_SPLUT);
} else {
obj.var[6] = 16; //fireball
obj.state = STATE::FLY;
obj.determineCurFrame();
obj.behavior = Knife;
}
obj.behave();
}
void BirdShot(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BULLET);
}
bool KnifeMask(float x, float y) {
return jjMaskedPixel(int(x), int(y)) && (jjEventAtLastMaskedPixel == 0 || jjEventAtLastMaskedPixel > AREA::HOOK);
}
void Knife(jjOBJ@ obj) {
if (obj.counter++ < 7) {
obj.xSpeed += obj.xAcc;
const float newX = obj.xPos + obj.xSpeed + obj.var[7]/65536.0;
obj.ySpeed += obj.yAcc;
const float newY = obj.yPos + obj.ySpeed;
if (KnifeMask(newX, newY)) {
obj.counter = 50; //return
} else {
obj.xPos = newX;
obj.yPos = newY;
}
} else {
jjPLAYER@ play = jjPlayers[obj.creatorID];
const float dx = play.xPos - obj.xPos;
const float dy = play.yPos - obj.yPos;
if ((abs(dx) < 18 && abs(dy) < 18) || (obj.state == STATE::DEACTIVATE && !jjDeactivatingBecauseOfDeath)) {
jjSamplePriority(SOUND::COMMON_PICKUPW1);
obj.delete();
if (play.ammo[WEAPON::BLASTER] <= AMMOBUFFER)
play.currWeapon = WEAPON::BLASTER;
play.ammo[WEAPON::BLASTER] = play.ammo[WEAPON::BLASTER] + 1;
return;
} else {
const float targetX = (dx > 0) ? 3 : -3;
const float targetY = (dy > 0) ? 2 : -2;
if (obj.xSpeed < targetX) obj.xSpeed += 0.1;
else if (obj.xSpeed > targetX) obj.xSpeed -= 0.1;
if (obj.ySpeed < targetY) obj.ySpeed += 0.1;
else if (obj.ySpeed > targetY) obj.ySpeed -= 0.1;
if (!KnifeMask(obj.xPos + obj.xSpeed, obj.yPos))
obj.xPos += obj.xSpeed;
else
obj.xSpeed = 0;
if (!KnifeMask(obj.xPos, obj.yPos + obj.ySpeed))
obj.yPos += obj.ySpeed;
else
obj.ySpeed = 0;
}
}
if (obj.counter > 3) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame);
if (++obj.counterEnd >= 5) {
obj.counterEnd = 0;
obj.frameID += 1;
obj.determineCurFrame();
}
}
}
array<jjMASKMAP@> FullMasks = {jjMASKMAP(false), jjMASKMAP(true)};
void SetFishMask(bool setTo) {
FullMasks[setTo ? 1 : 0].save(1040, false);
}
void NotSwimming(jjOBJ@) {
jjSetWaterLevel(jjLayerHeight[4] * 32, true);
SetFishMask(false);
}
void onLevelReload() {
MLLE::Palette.apply();
jjAddObject(OBJECT::BEES,0,0,0,CREATOR::OBJECT, NotSwimming);
for (int x = jjLayerWidth[3]; --x >= 0;)
for (int y = jjLayerHeight[3]; --y >= 0;) {
const uint8 ev = jjEventGet(x,y);
if (ev == 34) //ammo
jjParameterSet(x,y,1,1,0);
}
}
array<array<int>> Targets(0);
uint CurrentTargetID = 0;
bool SetTarget(uint nu) {
if (nu > CurrentTargetID) {
CurrentTargetID = nu;
return true;
}
return false;
}
void onFunction5(jjPLAYER@, uint8 nu) {
SetTarget(nu);
}
const int AMMOBUFFER = 10;
void onPlayer(jjPLAYER@ play) {
play.lives = 5;
if (play.health <= 0)
PlayersX[play.localPlayerID].Apples = 2;
play.fastfire = 8;
if (PlayersX[play.localPlayerID].Fish) {
play.spriteMode = SPRITE::INVISIBLE;
play.currWeapon = WEAPON::BLASTER;
jjWeapons[WEAPON::BLASTER].infinite = true;
play.keySelect = false;
play.jumpStrength = -5;
SetFishMask(true);
jjSetWaterLevel(PlayersX[play.localPlayerID].WaterLevel, true);
if (play.yPos <= jjWaterLevel) {
play.keyDown = play.keyFire = false;
if (play.ySpeed > 0)
play.keyJump = false;
}
float ySpeed = play.ySpeed;
if (ySpeed < -2.f) ySpeed = -2.f;
else if (ySpeed > 2.f) ySpeed = 2.f;
jjDrawRotatedSprite(play.xPos, play.yPos, ANIM::FISH, 1, jjGameTicks / 6, int(ySpeed * -64) * play.direction, play.direction, 1, SPRITE::PLAYER, play.playerID);
} else {
play.spriteMode = SPRITE::PLAYER;
NotSwimming(null);
if (play.charCurr == CHAR::FROG) {
play.jumpStrength = play.keyJump ? -18 : -7;
play.keyJump = true;
play.keyFire = false;
if (PlayersX[play.localPlayerID].Immobile)
play.keyLeft = play.keyRight = false;
} else if (play.charCurr == CHAR::BIRD2) {
play.currWeapon = WEAPON::BLASTER;
play.keySelect = false;
jjWeapons[WEAPON::BLASTER].infinite = true;
if (PlayersX[play.localPlayerID].Immobile) {
play.keyUp = play.keyDown = play.keyJump = play.keyFire = play.keyRun = false; //ONLY left/right allowed
play.ySpeed = -1.5;
play.invincibility = -200;
}
} else {
if (play.keySelect || play.ammo[WEAPON::CURRENT] <= AMMOBUFFER)
play.keyFire = false;
if (play.keyDown && !jjMaskedPixel(int(play.xPos), int(play.yPos) + 21) && (jjEventGet(int(play.xPos) >> 5, int(play.yPos) >> 5) != AREA::VINE))
play.keyDown = false;
if (PlayersX[play.localPlayerID].NoJumping > jjGameTicks)
play.keyJump = false;
jjWeapons[WEAPON::BLASTER].infinite = false;
play.jumpStrength = -10;
}
}
if (CurrentTargetID < Targets.length)
if (jjDifficulty <= 0 || jjKey[9])
ArtificialArrow::DrawArrow(Targets[CurrentTargetID], play, SPRITE::SINGLEHUE, 72);
}
class PacmanGhost : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.state = STATE::FLY;
obj.yPos -= 32;
if (jjParameterGet(int(obj.xOrg) >> 5, int(obj.yOrg) >> 5, 0, 1) == 1) {
obj.scriptedCollisions = false;
obj.playerHandling = HANDLING::ENEMY;
obj.bulletHandling = HANDLING::HURTBYBULLET;
obj.determineCurAnim(ANIM::BIRD, 9);
}
} else if (obj.state == STATE::FLY) {
obj.pathMovement();
if (++obj.counterEnd >= 6) {
obj.counterEnd = 0;
obj.frameID += 1;
obj.determineCurFrame();
}
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.scriptedCollisions ? obj.direction * -2 - 1 : obj.direction, obj.justHit == 0 ? SPRITE::NORMAL : SPRITE::SINGLECOLOR, 15);
} else if (obj.state == STATE::KILL) {
obj.deactivate();
} else { //freeze, deactivate
obj.behave(BEHAVIOR::SPARK);
}
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int) {
if (bullet !is null) {
if (bullet.behavior == BirdShot) {
obj.bulletHandling = HANDLING::HURTBYBULLET;
obj.scriptedCollisions = false;
bullet.objectHit(obj, HANDLING::ENEMY);
}
} else
play.objectHit(obj, 0, HANDLING::ENEMY);
return true;
}
}
void SpikeBall(jjOBJ@ obj) {
if (obj.state == STATE::DEACTIVATE || obj.state == STATE::EXPLODE || obj.state == STATE::KILL) {
jjPLAYER@ owner = jjPlayers[obj.creatorID];
owner.ammo[WEAPON::BOUNCER] = owner.ammo[WEAPON::BOUNCER] + 1;
obj.behavior = BEHAVIOR::BOUNCERBULLETPU;
}
obj.behave(BEHAVIOR::BOUNCERBULLETPU);
}
int getLivesAnimID(int character, bool swimming) {
if (!swimming) switch (character) {
case CHAR::JAZZ:
return jjAnimSets[ANIM::FACES] + 3;
case CHAR::SPAZ:
return jjAnimSets[ANIM::FACES] + (jjIsTSF ? 5 : 4);
case CHAR::LORI:
return jjAnimSets[ANIM::FACES] + 4;
case CHAR::FROG:
return jjAnimSets[ANIM::FACES] + 2;
case CHAR::BIRD:
case CHAR::BIRD2:
return jjAnimSets[ANIM::FACES] + 0;
}
return jjAnimSets[ANIM::CUSTOM[0]];
}
bool onDrawLives(jjPLAYER@ player, jjCANVAS@ canvas) {
const jjANIMATION@ anim = jjAnimations[getLivesAnimID(player.charCurr, PlayersX[player.localPlayerID].Fish)];
canvas.drawSpriteFromCurFrame(0, jjSubscreenHeight, anim.firstFrame + (jjGameTicks / 6) % anim.frameCount, 1, SPRITE::PLAYER, player.playerID);
int x = 20;
for (int keyType = 0; keyType < 2; ++keyType) {
for (uint i = 0; i < Keys[keyType]; ++i)
canvas.drawSpriteFromCurFrame(x += 30, jjSubscreenHeight - 20, KeyCurFrame - keyType);
}
jjLayerXOffset[2] =
jjLayerXOffset[2] + 2.5;
return true;
}
void onFunction0(jjPLAYER@ player, uint8 level) {
if (PlayersX[player.localPlayerID].Fish) {
int target;
if (level == 0) target = int(player.yPos) & ~31;
else target = level * 32;
PlayersX[player.localPlayerID].WaterLevel = target;
} else if (player.charCurr != CHAR::FROG) {
if (player.health > 0)
player.hurt(7, true);
}
}
void onFunction1(jjPLAYER@ player, bool canMove) {
if (player.charCurr == CHAR::FROG)
PlayersX[player.localPlayerID].Immobile = !canMove;
}
const array<CHAR::Char> paramToChar = {jjLocalPlayers[0].charOrig, CHAR::FROG, CHAR::BIRD2, CHAR::JAZZ};
class MorphHead : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.var[0] = jjParameterGet(int(obj.xOrg) >> 5, int(obj.yOrg) >> 5, 0, 2); //{Rabbit,Frog,Bird,Fish}
obj.var[1] = paramToChar[obj.var[0]];
obj.var[2] = jjParameterGet(int(obj.xOrg) >> 5, int(obj.yOrg) >> 5, 2, 1);
obj.curAnim = getLivesAnimID(obj.var[1], obj.var[0] == 3);
obj.state = STATE::FLOAT;
obj.special = 0;
obj.curFrame = jjAnimations[jjAnimSets[ANIM::AMMO] + 5] + 6;
} else if (obj.state == STATE::DEACTIVATE) {
obj.deactivate();
} else {
{
const int playerID = obj.findNearestPlayer(150 * 150);
if (playerID >= 0)
obj.direction = (jjPlayers[playerID].xPos >= obj.xPos) ? 1 : -1;
}
const jjANIMATION@ anim = jjAnimations[obj.curAnim];
jjDrawSpriteFromCurFrame(obj.xPos - 14 * obj.direction, obj.yPos + 16, anim.firstFrame + (jjGameTicks / 6) % anim.frameCount, obj.direction);
if (obj.special != 0 && (jjGameTicks & 7) == 0) {
obj.frameID = 100;
obj.state = STATE::ACTION;
obj.behave(BEHAVIOR::CHECKPOINT, false);
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ player = jjLocalPlayers[i];
player.xOrg = obj.xPos; //don't use checkpoints' curframe hotspot code, because lives icons have weird hotspots
player.yOrg = obj.yPos;
}
obj.curFrame = jjObjectPresets[obj.eventID].curFrame;
obj.special = 0;
obj.var[0] = jjParameterGet(int(obj.xOrg) >> 5, int(obj.yOrg) >> 5, 0, 2);
for (int x = jjLayerWidth[3]; --x >= 0;)
for (int y = jjLayerHeight[3]; --y >= 0;) {
const uint8 ev = jjEventGet(x,y);
if (ev == 34 && jjParameterGet(x,y,1,1) == 1) //ammo
jjEventSet(x,y, 0);
}
}
}
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int) {
if (bullet is null) {
if (obj.var[0] != 3) {
if (player.charCurr != obj.var[1] || PlayersX[player.localPlayerID].Fish) {
player.morphTo(CHAR::Char(obj.var[1]), true);
PlayersX[player.localPlayerID].Fish = false;
PlayersX[player.localPlayerID].NoJumping = jjGameTicks + 3;
if (player.charCurr == CHAR::BIRD2)
SetTarget(6);
else if (player.charCurr == CHAR::FROG)
SetTarget(11);
else if (player.charCurr == jjLocalPlayers[0].charOrig && player.ammo[WEAPON::BLASTER] > 0)
SetTarget(8);
} else return true;
} else {
if (!PlayersX[player.localPlayerID].Fish) {
player.morphTo(CHAR::JAZZ, true); //I guess
PlayersX[player.localPlayerID].Fish = true;
player.xPos = obj.xPos;
SetTarget(14);
} else return true;
}
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_HOLYFLUT);
obj.special = player.playerID + CREATOR::PLAYER; //to trigger checkpoint code
for (uint objectID = jjObjectCount; --objectID != 0;) { //delete bullets from this player, for better checkpoint oldAmmo numbers
jjOBJ@ bb = jjObjects[objectID];
if (bb.behavior == Knife && bb.creator == obj.special) {
player.ammo[WEAPON::BLASTER] =
player.ammo[WEAPON::BLASTER] + 1;
bb.delete();
} else if (bb.behavior == BEHAVIOR::BOUNCERBULLETPU && bb.creator == obj.special) {
player.ammo[WEAPON::BOUNCER] =
player.ammo[WEAPON::BOUNCER] + 1;
bb.delete();
}
}
if (obj.var[2] == 1) //nocheckpoint
obj.special = 0;
}
return true;
}
}
array<uint> Keys(2, 0);
class Key : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.special = jjParameterGet(int(obj.xOrg) >> 5, int(obj.yOrg) >> 5, 0, 1);
obj.curAnim -= obj.special;
}
if (obj.xSpeed != 0) {
obj.xSpeed = 0;
if (obj.ySpeed == 0) obj.ySpeed = 0.5;
}
obj.ySpeed = abs(obj.ySpeed);
if (obj.ySpeed > 3) obj.ySpeed = 3;
obj.behave(BEHAVIOR::PICKUP, false);
jjDrawSpriteFromCurFrame(obj.xPos, (obj.ySpeed != 0.f) ? obj.yPos : (obj.yPos + jjSin((obj.objectID*8+jjGameTicks+int(obj.xPos+obj.yPos*256))*16) * 4), obj.curFrame, obj.direction, SPRITE::NORMAL,0, 2);
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@, jjPLAYER@ player, int) {
obj.behavior = BEHAVIOR::EXPLOSION2;
obj.playerHandling = HANDLING::EXPLOSION;
Keys[obj.special] += 1;
jjEventSet(int(obj.xOrg) >> 5, int(obj.yOrg) >> 5, 0);
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_COIN);
if (obj.special == 0) { //key
if (player.charCurr != CHAR::FROG)
SetTarget(9);
else
SetTarget(12);
} else //gem
SetTarget(3);
return true;
}
}
class Lock : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.var[0] = jjParameterGet(int(obj.xOrg) >> 5, int(obj.yOrg) >> 5, 0, 2);
obj.var[1] = jjParameterGet(int(obj.xOrg) >> 5, int(obj.yOrg) >> 5, 2, 2);
obj.curAnim = KeyCurFrame - obj.var[0];
if (obj.var[0] == 3) obj.curAnim += 1;
obj.curFrame = jjAnimations[jjAnimSets[ANIM::DESTSCEN]] + 2;
obj.yPos += obj.var[1] * 16;
obj.state = STATE::WAIT;
} else if (obj.state == STATE::DEACTIVATE) {
obj.deactivate();
} else {
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curAnim, 256, 1, obj.var[0] != 2 ? 1 : -1, obj.var[0] <= 1 ? SPRITE::SINGLECOLOR : SPRITE::NORMAL, 0, 2);
}
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@, jjPLAYER@ player, int) {
if (obj.var[0] <= 1) { //key/gem
if (Keys[obj.var[0]] <= 0) {
if (obj.var[2] < jjGameTicks ) {
obj.var[2] = jjGameTicks + 210;
jjAnimations[jjObjectPresets[OBJECT::SILVERCOIN].curAnim].frameCount = 1;
jjAnimations[jjObjectPresets[OBJECT::SILVERCOIN].curAnim].firstFrame = KeyCurFrame - obj.var[0];
player.testForCoins(1);
SetTarget(2);
}
return true;
}
Keys[obj.var[0]] -= 1;
} else { //right/left
if ((obj.var[0] == 2) == (player.xPos >= obj.xPos))
return true;
}
const int xTile = int(obj.xOrg) >> 5, yTile = int(obj.yOrg) >> 5;
jjGenerateSettableTileArea(4, xTile,yTile, 1, obj.var[1] + 1);
jjEventSet(xTile,yTile, 0);
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_DAMPED1);
for (int y = 0; y <= obj.var[1]; ++y) {
const uint16 tileID = jjTileGet(4,xTile,yTile+y);
//jjAddParticleTileExplosion(xTile,yTile+y,tileID,false);
for (int q = 0; q < 4; ++q) {
jjPARTICLE@ part = jjAddParticle(PARTICLE::TILE);
if (part !is null) {
part.xPos = xTile * 32 + (q & 1) * 16;
part.yPos = (yTile + y) * 32 + (q & 2) * 8;
part.ySpeed = y - obj.var[1] + ((q & 2) / 4.f) - 1;
part.xSpeed = ((q & 1) * 2 - 1) / 2.f * (abs(part.ySpeed) + 1) / 1.75;
part.tile.tileID = tileID;
part.tile.quadrant = TILE::Quadrant(q);
}
}
jjTileSet(4,xTile,yTile+y,0);
}
obj.delete();
return true;
}
}
class Apple : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::PICKUP);
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@, jjPLAYER@ player, int) {
obj.behavior = BEHAVIOR::EXPLOSION2;
obj.playerHandling = HANDLING::EXPLOSION;
jjSample(obj.xPos, obj.yPos, SOUND::Sample(SOUND::COMMON_EAT1 + (jjRandom() & 3)));
if (player.health < jjMaxHealth) {
PlayerX@ playerX = PlayersX[player.localPlayerID];
if (playerX.Apples < 10) {
playerX.Apples += 1;
} else {
playerX.Apples = 2;
player.health += 1;
}
}
if (jjDifficulty > 2)
jjEventSet(int(obj.xOrg) >> 5, int(obj.yOrg) >> 5, 0);
return true;
}
}
const int HeartCurFrame = jjAnimations[jjAnimSets[ANIM::PICKUPS] + 41];
bool onDrawHealth(jjPLAYER@ player, jjCANVAS@ canvas) {
canvas.drawRectangle(jjSubscreenWidth - 51, 5, 44, 12, 30);
if (player.health > 0 && (player.health > 1 || jjRenderFrame & 3 < 2)) {
canvas.drawSpriteFromCurFrame(jjSubscreenWidth - 65, 11, HeartCurFrame);
canvas.drawRectangle(jjSubscreenWidth - 50, 6, (player.health - 1) * 10 + PlayersX[player.localPlayerID].Apples, 10, 24);
}
return true;
}
void GenerateWaterLayer() { //one-time
jjLAYER newLayer(jjLayerWidth[3], jjLayerHeight[3]);
newLayer.xSpeed = newLayer.ySpeed = 1;
dictionary createdTiles;
auto newTileID = jjTileCount;
for (int x = jjLayerWidth[3]; --x >= 0;)
for (int y = jjLayerHeight[3]; --y >= 0;) {
const uint16 waterTileID = jjTileGet(3,x,y);
if (waterTileID >= 1365 && waterTileID <= 1427) {
const uint16 wallTileID = jjTileGet(4,x,y);
if (wallTileID != 0) { //would this ever come up? well, no harm in it
const string combo = waterTileID + "_" + wallTileID;
uint16 comboTileID;
if (!createdTiles.get(combo, comboTileID)) {
comboTileID = newTileID++;
jjPIXELMAP water(waterTileID), wall(wallTileID);
for (uint xx = 0; xx < 32; ++xx)
for (uint yy = 0; yy < 32; ++yy)
if (water[xx,yy] != 0)
wall[xx,yy] = 0;
createdTiles.set(combo, comboTileID);
wall.save(comboTileID);
}
newLayer.generateSettableTileArea(x,y,1,1); //not the most efficient but we're probably not dealing with big enough numbers for it to be a problem
newLayer.tileSet(x,y,comboTileID);
}
}
}
auto layers = jjLayerOrderGet();
layers.insertAt(layers.findByRef(jjLayers[3]), newLayer);
jjLayerOrderSet(layers);
}
void FrogFencer(jjOBJ@ obj) {
if (obj.state == STATE::KILL) {
obj.deactivate();
} else if (obj.state == STATE::JUMP) {
if (obj.ySpeed < 0) {
if (jjMaskedPixel(int(obj.xPos), int(obj.yPos))) //hit ceiling
obj.ySpeed = 0;
}
if (jjMaskedVLine(int(obj.xPos + obj.xSpeed), int(obj.yPos) - 10, 15)) { //hit wall
obj.xPos -= obj.xSpeed;
}
} else if (obj.state == STATE::STILL) {
if (obj.counter & 7 == 3 && obj.frameID == 7) {
if ((obj.var[5] = (obj.var[5] ^ 1)) == 1)
jjSample(obj.xPos, obj.yPos, SOUND::FROG_FROG);
}
} else if (obj.state == STATE::START) {
obj.yPos -= 10;
}
obj.behave(BEHAVIOR::FENCER, false);
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos + 5, obj.curFrame, obj.direction);
}
class Ammo : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
if (obj.state == STATE::START) {
if (jjParameterGet(int(obj.xOrg) >> 5, int(obj.yOrg) >> 5, 0, 1) == 0) {
obj.determineCurAnim(ANIM::AMMO, 49);
obj.var[3] =
obj.var[3] - 1;
} else obj.determineCurAnim(ANIM::ROBOT, 0);
}
obj.behave(BEHAVIOR::PICKUP);
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@, jjPLAYER@ play, int) {
WEAPON::Weapon gunID = WEAPON::Weapon(obj.var[3] + 1);
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ player = jjLocalPlayers[i];
if (player.ammo[gunID] <= 0) {
player.ammo[gunID] = AMMOBUFFER;
player.currWeapon = gunID;
}
player.ammo[gunID] =
player.ammo[gunID] + 1;
}
obj.behavior = BEHAVIOR::EXPLOSION2;
obj.playerHandling = HANDLING::EXPLOSION;
jjParameterSet(int(obj.xOrg) >> 5, int(obj.yOrg) >> 5, 1, 1, 1);
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PICKUPW1);
if (gunID == WEAPON::BLASTER)
SetTarget((play.charCurr == CHAR::BIRD2) ? 7 : 8);
else
SetTarget(17);
return true;
}
}
bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
int x = jjSubscreenWidth - 24;
int y = jjSubscreenHeight - 20;
for (int weaponID = 1; weaponID <= 2; ++weaponID) {
const jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::BLASTERBULLET + weaponID - 1].curAnim];
const int ammo = player.ammo[weaponID] - AMMOBUFFER;
for (int b = 0; b < ammo; ++b)
canvas.drawSpriteFromCurFrame(x, y - b * 24, anim.firstFrame + (jjGameTicks / 6 + b) % anim.frameCount, 1, (uint(weaponID) == player.currWeapon && player.charCurr != CHAR::BIRD2 && !PlayersX[player.localPlayerID].Fish) ? SPRITE::NORMAL : SPRITE::BLEND_NORMAL, 96);
x -= 24;
}
return true;
}
bool onCheat(string &in cheat) {
if (cheat == "jjammo" || cheat == "jjguns" || cheat == "jjgod") {
for (int i = 0; i < jjLocalPlayerCount; ++i)
for (int w = 1; w <= 2; ++w) {
if (jjLocalPlayers[i].ammo[w] == 0)
jjLocalPlayers[i].ammo[w] = AMMOBUFFER;
jjLocalPlayers[i].ammo[w] =
jjLocalPlayers[i].ammo[w] + 1;
}
jjAlert(cheat, false, STRING::MEDIUM);
return true;
} else if (cheat == "jjmorph") {
return true;
}
return false;
}
void onFunction3() {
for (int x = jjLayerWidth[3]; --x >= 0;)
for (int y = jjLayerHeight[3]; --y >= 0;) {
const uint8 ev = jjEventGet(x,y);
if (ev == 146) //morph head
jjEventSet(x,y, 0);
else if (ev == 255) {
jjEventSet(x,y, jjParameterGet(x,y,0,8));
}
}
}
void onFunction4(jjPLAYER@ play) {
MLLE::GetLayer("River").hasTiles = false;
MLLE::GetLayer("Far Trees").hasTiles = false;
MLLE::GetLayer("Farther Trees").hasTiles = false;
MLLE::GetLayer("Owls").hasTiles = false;
jjTexturedBGUsed = false;
jjMusicStop();
PlayersX[play.localPlayerID].Immobile = true;
SetTarget(22);
}
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.