Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Mystery of the Four... | chandie | Single player | 6.6 |
const bool MLLESetupSuccessful = MLLE::Setup(array<MLLEWeaponApply@> = {null, null, DefaultWeapons::Blaster(), DefaultWeapons::Blaster(), WeaponVMega::Backfire::Weapon(), null, null, null, DefaultWeapons::Blaster()}); ///@MLLE-Generated
#include "MLLE-Include-1.5w.asc" ///@MLLE-Generated
#pragma require "mo4a_1-2-MLLE-Data-1.j2l" ///@MLLE-Generated
#pragma require "mo4a_1-2.j2l" ///@MLLE-Generated
#include "WeaponVMega5.asc" ///@MLLE-Generated
#pragma require "WeaponVMega5.asc" ///@MLLE-Generated
#include "MLLE-DefaultWeapons.asc" ///@MLLE-Generated
#pragma require "MLLE-DefaultWeapons.asc" ///@MLLE-Generated
#include "Jazz1Enemies v05.asc"
#include "Resize v11.asc"
#include "TrueColor v13.asc"
#include "HH18savegems.asc"
#pragma require "kangaroo.j2a"
const OBJECT::Object JillEventID = OBJECT::FENCER;
int LaserFrog = 0, exit = 0, frogexit = 0;
bool crate2 =false, crate3 = false, crate5 = false, crate6 = false, control = true;
bool froggy = false, doorunblocked = false, startrush = false, readytorush = false, womensaved = false;
void onPlayer(jjPLAYER@ play) {
jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::ORANGE].curAnim];
anim.frameCount = 1;
jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
jjPIXELMAP fruit(0, 31*32, 1*32, 1*32, 5);
fruit.save(frame);
for (int i = 0; i < 1024; i++) { //loop through the global array jjParticles[1024]
jjPARTICLE@ particle = jjParticles[i];
if (particle.type == PARTICLE::RAIN) {
particle.xSpeed = 0; //make rain fall straight down
particle.ySpeed = play.ySpeed < 0? 10 : int(10 + play.ySpeed); //the rain speed accounts for differences in the player speed, and so won't appear to fall more slowly when the player is falling
}
}
if(jjTriggers[15] == false)
{jjEnabledASFunctions[2] = true;}
if(jjTriggers[14] == false)
{jjEnabledASFunctions[8] = true;}
if(jjTriggers[13] == false)
{jjEnabledASFunctions[7] = true;}
if(jjTriggers[12] == false)
{jjEnabledASFunctions[6] = true;}
if(jjTriggers[1] == false)
{jjEnabledASFunctions[5] = true;}
if(jjTriggers[10] == false)
{jjEnabledASFunctions[4] = true;}
frogexit = 0;
if(jjTriggers[2] == true)
{frogexit += 1;
crate2 = true;}
if(jjTriggers[3] == true)
{frogexit += 1;
crate3 = true;}
if(jjTriggers[5] == true)
{frogexit += 1;
crate5 = true;}
if(jjTriggers[6] == true)
{frogexit += 1;
crate6 = true;}
exit = 0;
if(jjTriggers[15] == true)
{exit += 1;}
if(jjTriggers[14] == true)
{exit += 1;}
if(jjTriggers[13] == true)
{exit += 1;}
if(jjTriggers[12] == true)
{exit += 1;}
if(jjTriggers[1] == true)
{exit += 1;}
if(jjTriggers[10] == true)
{exit += 1;}
gem::trackPlayerGems(p);
gem::upgradeHealth(p);
if(womensaved == false && jjTriggers[10] == true && jjTriggers[1] == true && jjTriggers[12] == true && jjTriggers[13] == true && jjTriggers[14] == true && jjTriggers[15] == true)
{p.showText("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Coin unlocked.");
womensaved = true;}
if(p.food == 100 && jjKey[0x52] == false && startrush == false)
{p.showText("@@@@@@@@@@@@@@@@||||||||Press 'R' when you need to use Sugar Rush!", STRING::MEDIUM);
p.startSugarRush(0);
startrush = true;
readytorush = true;}
if(readytorush == true)
{p.food = 100;}
if(p.food == 100 && jjKey[0x52])
{p.startSugarRush(1400);
p.food = 0;
readytorush = false;
startrush = false;
}
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ o = jjObjects[i];
if (o.isActive && o.eventID == OBJECT::SILVERCOIN && p.coins >= 2) {
o.state = STATE::KILL;
}
}
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ o = jjObjects[i];
if (o.isActive && o.eventID == OBJECT::SEEKERAMMO3 && p.ammo[WEAPON::SEEKER] < 1) {
o.state = STATE::KILL;}
}
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ o = jjObjects[i];
if (o.isActive && o.eventID == OBJECT::RFAMMO3 && p.ammo[WEAPON::RF] < 1) {
o.state = STATE::KILL;}
}
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ o = jjObjects[i];
if (o.isActive && o.eventID == OBJECT::TNTAMMO3 && p.ammo[WEAPON::TNT] < 1) {
o.state = STATE::KILL;}
}
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ o = jjObjects[i];
if (o.isActive && o.eventID == OBJECT::GUN9AMMO3 && p.ammo[WEAPON::GUN9] < 1) {
o.state = STATE::KILL;}
}
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ o = jjObjects[i];
if (o.isActive && o.eventID == OBJECT::SEEKERPOWERUP && p.ammo[WEAPON::SEEKER] < 1) {
o.state = STATE::KILL;}
}
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ o = jjObjects[i];
if (o.isActive && o.eventID == OBJECT::RFPOWERUP && p.ammo[WEAPON::RF] < 1) {
o.state = STATE::KILL;}
}
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ o = jjObjects[i];
if (o.isActive && o.eventID == OBJECT::TNTPOWERUP && p.ammo[WEAPON::TNT] < 1) {
o.state = STATE::KILL;}
}
for (int i = 1; i < jjObjectCount; i++) {
jjOBJ@ o = jjObjects[i];
if (o.isActive && o.eventID == OBJECT::GUN9POWERUP && p.ammo[WEAPON::GUN9] < 1) {
o.state = STATE::KILL;}
}
if (doorunblocked == false && jjTriggers[2]==true && jjTriggers[3]==true && jjTriggers[5]==true && jjTriggers[6]==true) {
p.showText("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Cage door's key activated.");
doorunblocked = true;}
if(p.yPos<4*32 && p.xPos>95*32 && p.xPos<99*32 && p.coins < 2)
{p.testForCoins(2);}
if(p.yPos<4*32 && p.xPos>95*32 && p.xPos<99*32 && p.coins == 2)
{jjNxt("mo4a_1-3_save", false, true);
gem::saveGemData();}
if(p.charCurr == CHAR::FROG) {
p.furSet(64, 64, 64, 64);
}
if(p.charCurr != CHAR::FROG) {
p.furSet(0, 0, 0, 0);
}
if(froggy == true) {
jjTriggers[20] = true;
}
if(p.coins==0)
{p.coins +=1;}
if(control==false)
{p.keyLeft = false;
p.keyRight = false;
p.keyDown = false;}
if(p.idle > 100)
{p.cameraUnfreeze(true);
control=true;}
else if (p.idle > 30 && (p.keyLeft || p.keyRight || p.keyJump || p.keyFire || p.keyFire))
{p.cameraUnfreeze(true);
control=true;}
if(play.keyUp == true && p.xPos>225*32 && p.xPos<228*32 && p.yPos<51*32 && p.yPos>49*32 && jjTriggers[2]==false){
jjTriggers[2] = true;
p.cameraFreeze(208*32, 48*32, true, false);
control = false;
jjSample(p.xPos, p.yPos, SOUND::INTRO_MONSTER2);}
if(play.keyUp == true && p.xPos<3*32 && p.yPos<4*32 && jjTriggers[7]==false){
jjTriggers[7] = true;
p.cameraFreeze(49*32, 12*32, true, false);
control = false;
jjSample(p.xPos, p.yPos, SOUND::INTRO_MONSTER2);}
if(play.keyUp == true && p.xPos>5*32 && p.xPos<8*32 && p.yPos>56*32 && p.yPos<59*32 && jjTriggers[8]==false){
jjTriggers[8] = true;
p.cameraFreeze(8*32, 38*32, true, false);
control = false;
jjSample(p.xPos, p.yPos, SOUND::INTRO_MONSTER2);}
if(play.keyUp == true && p.xPos>248*32 && p.xPos<251*32 && p.yPos<57*32 && p.yPos>54*32 && jjTriggers[9]==false){
jjTriggers[9] = true;
jjSample(p.xPos, p.yPos, SOUND::INTRO_MONSTER2);}
if(play.keyUp == true && p.xPos>248*32 && p.xPos<251*32 && p.yPos<25*32 && p.yPos>22*32 && jjTriggers[11]==false){
jjTriggers[11] = true;
jjSample(p.xPos, p.yPos, SOUND::INTRO_MONSTER2);}
if(play.yPos > jjWaterLevel && play.charCurr == CHAR::FROG && p.keyJump == true)
{play.jumpStrength = -10;}
if(play.yPos > jjWaterLevel && play.charCurr != CHAR::FROG)
{play.health = 0;}
play.lightType = LIGHT::NONE;
if(LaserFrog < jjGameTicks)
{p.invisibility = false;}
if (LaserFrog > jjGameTicks) {
p.invisibility = false;
if(play.keyFire) {
p.invisibility = true;
p.lightType = LIGHT::LASER;
jjDrawSprite(p.xPos, p.yPos, p.setID, RABBIT::EARBRACHIATE, p.curFrame, p.direction, SPRITE::PLAYER);
if(jjRandom() & 9 == 0){
jjOBJ@ obj = jjObjects[OBJECT::LASER];
jjAddObject(OBJECT::LASER, -p.xPos, p.yPos);
obj.behave(BEHAVIOR::BULLET);
obj.determineCurAnim(ANIM::AMMO, 60);
obj.playerHandling = HANDLING::PLAYERBULLET;
obj.bulletHandling = HANDLING::IGNOREBULLET;
}
}
}
}
void onLevelLoad() {
jjPIXELMAP rain(32,32);
for (uint x = 0; x < rain.width; ++x) {
for (uint y = 0; y < rain.height; ++y) {
if (x == 16) { //draw in the middle of the tile, xPixel 16
if (y <= 24) rain[x,y] = 75; //if at yPixel 24 or less, use color 75
else rain[x,y] = 74; //use color 74 for yPixels 25-32
} else {
rain[x,y] = 0;
}
}
}
jjANIMATION@ anim = jjAnimations[jjAnimSets[ANIM::COMMON].firstAnim + 2];
for (uint frameID = 0; frameID < anim.frameCount; ++frameID) {
jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame + frameID];
rain.save(frame);
frame.hotSpotX = -frame.width/2;
frame.hotSpotY = -frame.height;
}
jjWaterLighting = WATERLIGHT::GLOBAL;
gem::restorePlayerGems();
jjLevelName = ("@@@@@@@@@Sacred Woods");
jjObjectPresets[OBJECT::SAVEPOST].behavior = CheckpointWrapper;
jjObjectPresets[OBJECT::SAVEPOST].deactivates = false;
jjObjectPresets[OBJECT::FISH].determineCurAnim(ANIM::FROG, 2);
jjObjectPresets[OBJECT::FISH].scriptedCollisions = true;
jjObjectPresets[OBJECT::FISH].direction = 1;
jjObjectPresets[OBJECT::FISH].playerHandling = HANDLING::SPECIAL;
jjObjectPresets[OBJECT::FISH].bulletHandling = HANDLING::IGNOREBULLET;
jjObjectPresets[OBJECT::FISH].putOnGround();
jjObjectPresets[OBJECT::FISH].behavior = FrogWait;
Jazz1::MakeEnemy(OBJECT::HATTER, Jazz1::Enemies::Marbelara_Schwarzenguard, true).SetUsesJJ2StyleDeathAnimation(true).SetBulletFireSound(SOUND::INTRO_SHOT1).SetBulletExplosionSound(SOUND::COMMON_GUNSM1);
jjObjectPresets[OBJECT::AIRBOARD].behavior = Key();
jjObjectPresets[OBJECT::AIRBOARD].scriptedCollisions = true;
jjObjectPresets[OBJECT::SEEKERPOWERUP].behavior = Switch1();
jjObjectPresets[OBJECT::SEEKERPOWERUP].scriptedCollisions = true;
jjObjectPresets[OBJECT::TOASTERPOWERUP].behavior = Switch2();
jjObjectPresets[OBJECT::TOASTERPOWERUP].scriptedCollisions = true;
jjObjectPresets[OBJECT::BOUNCERPOWERUP].behavior = Switch3();
jjObjectPresets[OBJECT::BOUNCERPOWERUP].scriptedCollisions = true;
jjObjectPresets[OBJECT::BLASTERPOWERUP].behavior = Switch4();
jjObjectPresets[OBJECT::BLASTERPOWERUP].scriptedCollisions = true;
jjObjectPresets[OBJECT::EXTRATIME].behavior = Laser();
jjObjectPresets[OBJECT::EXTRATIME].scriptedCollisions = true;
jjObjectPresets[OBJECT::SILVERCOIN].behavior = PlatinCoin();
jjObjectPresets[OBJECT::SILVERCOIN].scriptedCollisions = true;
jjObjectPresets[OBJECT::TRIGGERCRATE].deactivates = false;
jjObjectPresets[OBJECT::FLYCARROT].determineCurAnim(ANIM::PLUS_WARP, 0);
jjObjectPresets[OBJECT::FLYCARROT].behavior = Bonus;
jjObjectPresets[OBJECT::FLYCARROT].scriptedCollisions = true;
jjANIMATION@ BAnim = jjAnimations[jjObjectPresets[OBJECT::FLYCARROT].curAnim];
for (uint i = 0; i < BAnim.frameCount; ++i)
jjAnimFrames[BAnim.firstFrame + i].hotSpotY = -85;
for (uint i = 0; i < BAnim.frameCount; ++i)
jjAnimFrames[BAnim.firstFrame + i].hotSpotX = 20;
jjObjectPresets[OBJECT::INVINCIBILITY].determineCurAnim(ANIM::PLUS_WARP, 1);
jjObjectPresets[OBJECT::INVINCIBILITY].behavior = Bonuseye;
jjObjectPresets[OBJECT::INVINCIBILITY].scriptedCollisions = true;
jjANIMATION@ BeAnim = jjAnimations[jjObjectPresets[OBJECT::INVINCIBILITY].curAnim];
for (uint i = 0; i < BeAnim.frameCount; ++i)
jjAnimFrames[BeAnim.firstFrame + i].hotSpotY = 32;
for (uint i = 0; i < BeAnim.frameCount; ++i)
jjAnimFrames[BeAnim.firstFrame + i].hotSpotX = 26;
jjEventSet(197, 11, JillEventID);
//call a couple Kangaroo functions
Kangaroo::MakeEventJoey(OBJECT::MONKEY); //default parameters
Kangaroo::MakeEventJoey(OBJECT::STANDMONKEY, 0, 5, 5, 12, 5, 256); //custom parameters
Kangaroo::MakeEventJill(
JillEventID
).deactivates = false; //note that both MakeEventJoey and MakeEventJill return the jjObjectPresets entry of the eventID passed to them
}
void Bonuseye(jjOBJ@ obj){
obj.direction = -1;
obj.behave(BEHAVIOR::PICKUP, false);
obj.draw();
}
void Bonus(jjOBJ@ obj){
obj.putOnGround();
obj.direction = -1;
obj.behave(BEHAVIOR::PICKUP, false);
obj.draw();
}
void FrogWait(jjOBJ@ obj) {
obj.behave(BEHAVIOR::FISH, false);
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::SINGLEHUE, 64);
}
bool cointext = true;
class PlatinCoin : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
if(p.coins >= 2)
{obj.delete();}
obj.behave(BEHAVIOR::PICKUP, false);
++obj.counter;
obj.yPos = jjSin(obj.counter*15 + 5)*4 + obj.yOrg;
if(jjTriggers[10] == true && jjTriggers[1] == true && jjTriggers[12] == true && jjTriggers[13] == true && jjTriggers[14] == true && jjTriggers[15] == true)
{jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, -8);}
else jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::TRANSLUCENTPALSHIFT, -8);
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
if(jjTriggers[10] == true && jjTriggers[1] == true && jjTriggers[12] == true && jjTriggers[13] == true && jjTriggers[14] == true && jjTriggers[15] == true)
{p.coins += 1;
obj.behavior = BEHAVIOR::EXPLOSION2;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_COIN, 1000);}
else if(cointext == true)
{p.showText("@@Save the women to@unlock the token.");
cointext=false;}
return true;
}
}
bool keytext = true;
class Key : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
if(jjTriggers[0]==true)
{obj.delete();}
obj.behave(BEHAVIOR::PICKUP, false);
jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::AIRBOARD].curAnim];
anim.frameCount = 1;
jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
jjPIXELMAP pump(0, 59*32, 1*32, 1*32, 5);
pump.save(frame);
++obj.counter;
obj.yPos = jjSin(obj.counter*15 + 5)*4 + obj.yOrg;
if(jjTriggers[2] == true && jjTriggers[3] == true && jjTriggers[5] == true && jjTriggers[6] == true)
{jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NORMAL);}
else {jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::TRANSLUCENT);}
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
if(jjTriggers[2] == true && jjTriggers[3] == true && jjTriggers[5] == true && jjTriggers[6] == true)
{
jjTriggers[0]=true;
obj.behavior = BEHAVIOR::EXPLOSION2;
jjSample(obj.xPos, obj.yPos, SOUND::MENUSOUNDS_TYPEENTER, 1000);
}
if(keytext==true) {
p.showText("@@@Find 4 metal crates@to activate this key.");
keytext = false;}
return true;
}
}
void onFunction0(jjPLAYER@ play) {
if(p.charCurr == CHAR::FROG) {
play.boss=jjAddObject(OBJECT::FISH, 103*32, 51*32);
froggy = true;
p.xPos = 104*32;
p.yPos = 60*32;
p.cameraFreeze(99*32, 57*32, true, false);
//control = false;
}
}
void onFunction1(jjPLAYER@ play) {
jjTriggers[20] = true;
p.revertMorph(false);
p.cameraUnfreeze();
froggy = true;
}
void onFunction2(jjPLAYER@ play) {
if(p.charCurr != CHAR::FROG && jjTriggers[15] == false) {
play.activateBoss();
jjMusicLoad("mo4a_Doc's Cave.ogg");
jjEnabledASFunctions[2] = false;
}
}
void onFunction3(jjPLAYER@ play) {
if(froggy == false)
p.morphTo(CHAR::FROG, false);
}
void onFunction4(jjPLAYER@ p) {
p.showText("@@You are free to go now.");
jjTriggers[10] = true;
exit += 1;
jjSample(p.xPos, p.yPos, SOUND::LORISOUNDS_LORIFALL);
}
void onFunction5(jjPLAYER@ p) {
p.showText("@@You are free to go now.");
jjSample(p.xPos, p.yPos, SOUND::LORISOUNDS_LORIFALL);
exit += 1;
jjTriggers[1] = true;
}
void onFunction6(jjPLAYER@ p) {
p.showText("@@You are free to go now.");
jjSample(p.xPos, p.yPos, SOUND::LORISOUNDS_LORIFALL);
exit += 1;
jjTriggers[12] = true;
}
void onFunction7(jjPLAYER@ p) {
p.showText("@@You are free to go now.");
jjSample(p.xPos, p.yPos, SOUND::LORISOUNDS_LORIFALL);
exit += 1;
jjTriggers[13] = true;
}
void onFunction8(jjPLAYER@ p) {
p.showText("@@You are free to go now.");
jjSample(p.xPos, p.yPos, SOUND::LORISOUNDS_LORIFALL);
exit += 1;
jjTriggers[14] = true;
}
class Laser : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::PICKUP, false);
obj.determineCurAnim(ANIM::AMMO, 58);
++obj.counter;
obj.yPos = jjSin(obj.counter*15 + 5)*4 + obj.yOrg;
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, 56);
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@, jjPLAYER@ play, int force) {
LaserFrog= jjGameTicks + 5 * 61;
p.timerStart(300);
obj.behavior = BEHAVIOR::EXPLOSION2;
obj.frameID = 0;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PICKUP1, 6000);
return true;
}
}
class Switch1: jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::PICKUP, false);
obj.draw();
jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::SEEKERPOWERUP].curAnim];
anim.frameCount = 1;
jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
jjPIXELMAP sw(0, 30*32, 1*32, 1*32, 5);
sw.save(frame);
frame.hotSpotY = 17;
frame.hotSpotX = -17;
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) {
obj.playerHandling = HANDLING::ENEMY;
obj.scriptedCollisions = false;
jjSwitchTrigger(8);
jjSample(p.xPos, p.yPos, SOUND::COMMON_EXPSM1, 3000);
obj.frameID = 0;
obj.behavior = BEHAVIOR::EXPLOSION2;
return true;
}
}
class Switch2: jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::PICKUP, false);
obj.draw();
jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::TOASTERPOWERUP].curAnim];
anim.frameCount = 1; //The Bee enemy's animation has several frames, but the tileset only has material for one. Editing jjANIMATION::frameCount to 1 will ensure that the animation never extends beyond the one frame we're providing.
jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
jjPIXELMAP pump(0, 30*32, 1*32, 1*32, 5);
pump.save(frame);
frame.hotSpotY = 17;
frame.hotSpotX = -17;
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) {
obj.playerHandling = HANDLING::ENEMY;
obj.scriptedCollisions = false;
jjSwitchTrigger(7);
jjSample(p.xPos, p.yPos, SOUND::COMMON_EXPSM1, 3000);
obj.frameID = 0;
obj.behavior = BEHAVIOR::EXPLOSION2;
return true;
}
}
class Switch3: jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::PICKUP, false);
obj.draw();
jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::BOUNCERPOWERUP].curAnim];
anim.frameCount = 1; //The Bee enemy's animation has several frames, but the tileset only has material for one. Editing jjANIMATION::frameCount to 1 will ensure that the animation never extends beyond the one frame we're providing.
jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
jjPIXELMAP pump(0, 30*32, 1*32, 1*32, 5);
pump.save(frame);
frame.hotSpotY = 17;
frame.hotSpotX = -15;
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) {
obj.playerHandling = HANDLING::ENEMY;
obj.scriptedCollisions = false;
jjSwitchTrigger(9);
jjSample(p.xPos, p.yPos, SOUND::COMMON_EXPSM1, 3000);
obj.frameID = 0;
obj.behavior = BEHAVIOR::EXPLOSION2;
return true;
}
}
class Switch4: jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::PICKUP, false);
obj.draw();
jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::BLASTERPOWERUP].curAnim];
anim.frameCount = 1; //The Bee enemy's animation has several frames, but the tileset only has material for one. Editing jjANIMATION::frameCount to 1 will ensure that the animation never extends beyond the one frame we're providing.
jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
jjPIXELMAP pump(0, 30*32, 1*32, 1*32, 5);
pump.save(frame);
frame.hotSpotY = 17;
frame.hotSpotX = -17;
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) {
obj.playerHandling = HANDLING::ENEMY;
obj.scriptedCollisions = false;
jjSwitchTrigger(11);
jjSample(p.xPos, p.yPos, SOUND::COMMON_EXPSM1, 3000);
obj.frameID = 0;
obj.behavior = BEHAVIOR::EXPLOSION;
return true;
}
}
void onMain() {
jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::BURGER].curAnim];
anim.frameCount = 1;
jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
jjPIXELMAP woman(0, 32*32, 1*32, 1*32, 5);
woman.save(frame);
frame.hotSpotY = -27;
gem::deleteCollectedGems();
if(jjTriggers[20]==true){
if(jjKey[9] && jjKey[0x51]) {
p.morphTo(CHAR::JAZZ, false);
}
if(jjKey[9] && jjKey[0x57]) {
p.morphTo(CHAR::SPAZ, false);
}
if(jjKey[9] && jjKey[0x45]) {
p.morphTo(CHAR::LORI, false);
}
}
}
/*
// *Kangaroo by VioletCLM.* I wanted to use a jjAddObject instead of jjNxt after the defeat of Jill. So I had to carry the contents of the ASC folder here and make a small arrangement. Sorry about that Violet.
API (all expected to be called in onLevelLoad):
jjOBJ@ Kangaroo::MakeEventJoey(uint8 eventID, int minX = 0, int maxX = 4, int minY = 6, int maxY = 12, int jumpDelay = 35, int minDistance = 224)
Assign a specific event slot to the Joey enemy, e.g. replacing another enemy type or a food object or something. If you assign multiple event slots, you can get Joey enemies with different parameters.
jjOBJ@ Kangaroo::MakeEventJill(uint8 eventID, uint8 spawn = 0, bool secondStage = false, int textID = -1)
Assign a specific event slot to the Jill boss.
"spawn", if non-zero, is an eventID that the boss will occasionally create from her pouch. This is assumed to be a Joey enemy but may be other objects as well.
The "secondStage" bool causes Jill to turn red and jump faster after she has lost three-quarters of her health.
If "textID" is 0-16, defeating Jill will display that text ID.
void Kangaroo::OnJillDefeat(JILLCALLBACKFUNC@ callback = null)
Three seconds after defeating Jill, this function will be called. The JILLCALLBACKFUNC pattern is the same as the behavior pattern: a void-returning function taking a jjOBJ@ as its only argument. If "callback" is left null, or if OnJillDefeat is never called, defeating a Jill will simply end the level.
void Kangaroo::Joey(jjOBJ@ obj)
The behavior function for the Joey enemy
void Kangaroo::Jill(jjOBJ@ obj)
The behavior function for the Jill boss
*/
namespace Kangaroo {
namespace Private {
void jillDefeatedDefaultAction(jjOBJ@ o) {
p.showText("@@You are free to go now.");
jjTriggers[15] = true;
jjAddObject(OBJECT::SAVEPOST, 204*32, 13*32);
exit += 1;
jjSample(p.xPos, p.yPos, SOUND::LORISOUNDS_LORIFALL);
jjMusicLoad("mo4a_The Golden City.ogg");
p.bossActivated = false;
}
JILLCALLBACKFUNC@ jillCallback = jillDefeatedDefaultAction;
bool animsLoaded = false;
uint customAnimID = 0;
void loadAnims() {
if (!animsLoaded) {
animsLoaded = true;
while (jjAnimSets[ANIM::CUSTOM[customAnimID]] != 0)
++customAnimID;
customAnimID = ANIM::CUSTOM[customAnimID];
jjAnimSets[customAnimID].load(0, "kangaroo.j2a");
if (!jjSampleIsLoaded(SOUND::BUBBA_BUBBABOUNCE1))
jjAnimSets[ANIM::BUBBA].load();
}
}
void applyGenericEnemySettingsToPreset(jjOBJ@ preset) {
preset.playerHandling = HANDLING::ENEMY;
preset.bulletHandling = HANDLING::HURTBYBULLET;
preset.causesRicochet = false;
preset.isBlastable = false;
preset.triggersTNT = true;
preset.isFreezable = true;
preset.isTarget = true;
preset.scriptedCollisions = false;
preset.direction = 1;
preset.freeze = 0;
}
void putKangarooOnGround(jjOBJ@ obj, int width, int height) {
while (!jjMaskedHLine(int(obj.xPos) - width/2, width, int(obj.yPos) + height/2))
obj.yPos += 1;
}
uint firstGloveAnimationFrame;
const jjANIMFRAME@ roundExplosionFrame = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::AMMO] + 5] + 2];;
void doGloveAt(int x, int y) {
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ localPlayer = jjLocalPlayers[i];
if (localPlayer.blink == 0 && roundExplosionFrame.doesCollide(x, y, 0, jjAnimFrames[localPlayer.curFrame], int(localPlayer.xPos), int(localPlayer.yPos), localPlayer.direction))
localPlayer.hurt();
}
for (int i = jjObjectCount - 1; i > 0; --i) {
jjOBJ@ obj = jjObjects[i];
if (obj.playerHandling == HANDLING::PLAYERBULLET && obj.state != STATE::EXPLODE && roundExplosionFrame.doesCollide(x, y, 0, jjAnimFrames[obj.curFrame], int(obj.xPos), int(obj.yPos), obj.direction)) {
obj.ricochet();
//obj.playerHandling = HANDLING::ENEMYBULLET;
}
}
}
}
enum KangarooVariables {
kvWIDTH = 0, kvHEIGHT, kvMINX, kvMAXX, kvMINY, kvMAXY, kvJUMPDELAY, kvMINDISTANCE, kvGLOVE1FRAME, kvGLOVE2FRAME, kvSECONDSTAGE
}
jjOBJ@ MakeEventJoey(uint8 eventID, int minX = 0, int maxX = 4, int minY = 6, int maxY = 12, int jumpDelay = 35, int minDistance = 224) {
Kangaroo::Private::loadAnims();
jjOBJ@ preset = jjObjectPresets[eventID];
preset.behavior = Joey;
preset.determineCurAnim(Kangaroo::Private::customAnimID, 0);
preset.frameID = 0; preset.determineCurFrame();
Kangaroo::Private::applyGenericEnemySettingsToPreset(preset);
preset.deactivates = true;
preset.energy = 1;
preset.points = 200;
preset.yAcc = 0.33f;
preset.counter = 0;
preset.var[kvWIDTH] = 12;
preset.var[kvHEIGHT] = 28;
preset.var[kvMINX] = minX;
preset.var[kvMAXX] = maxX;
preset.var[kvMINY] = minY;
preset.var[kvMAXY] = maxY;
preset.var[kvJUMPDELAY] = jumpDelay;
preset.var[kvMINDISTANCE] = minDistance;
return preset;
}
funcdef void JILLCALLBACKFUNC(jjOBJ@);
jjOBJ@ MakeEventJill(uint8 eventID, uint8 spawn = 0, bool secondStage = false, int textID = -1) {
Kangaroo::Private::loadAnims();
if (jjAnimSets[ANIM::GLOVE] == 0)
jjAnimSets[ANIM::GLOVE].load();
Kangaroo::Private::firstGloveAnimationFrame = jjAnimations[jjAnimSets[ANIM::GLOVE] + 3];
jjOBJ@ preset = jjObjectPresets[eventID];
preset.behavior = Jill;
preset.determineCurAnim(Kangaroo::Private::customAnimID, 1);
preset.frameID = 0; preset.determineCurFrame();
Kangaroo::Private::applyGenericEnemySettingsToPreset(preset);
preset.doesHurt = spawn;
preset.yAcc = 0.16f;
preset.energy = 100;
preset.points = 5000;
preset.counterEnd = 210; //death wait
preset.special = textID;
preset.playerHandling = HANDLING::DYING; //no initial collision damage
preset.var[kvWIDTH] = 32;
preset.var[kvHEIGHT] = 98;
preset.var[kvMINX] = 2;
preset.var[kvMAXX] = 4;
preset.var[kvMINY] = 5;
preset.var[kvMAXY] = 10;
preset.var[kvJUMPDELAY] = 140;
preset.var[kvMINDISTANCE] = 400;
preset.var[kvGLOVE1FRAME] = 0;
preset.var[kvGLOVE2FRAME] = 0;
preset.var[kvSECONDSTAGE] = secondStage ? 1 : 0;
return preset;
}
void OnJillDefeat(JILLCALLBACKFUNC@ callback = null) {
if (callback !is null)
@Kangaroo::Private::jillCallback = callback;
}
void Joey(jjOBJ@ obj) {
const int width = obj.var[kvWIDTH];
const int height = obj.var[kvHEIGHT];
switch (obj.state) {
case STATE::START:
obj.state = STATE::IDLE;
Kangaroo::Private::putKangarooOnGround(obj, width, height);
case STATE::IDLE:
if (obj.counter == 0 || --obj.counter == 0) {
const int nearestPlayerID = obj.findNearestPlayer(int(pow(obj.var[kvMINDISTANCE], 2)));
if (nearestPlayerID >= 0) {
jjPLAYER@ nearestPlayer = jjPlayers[nearestPlayerID];
obj.xSpeed = (nearestPlayer.xPos - obj.xPos) / 20.0f;
obj.direction = (obj.xSpeed >= 0) ? 1 : -1;
float xSpeed = abs(obj.xSpeed);
if (xSpeed > obj.var[kvMAXX]) xSpeed = obj.var[kvMAXX];
else if (xSpeed < obj.var[kvMINX]) xSpeed = obj.var[kvMINX];
obj.xSpeed = xSpeed * obj.direction;
float ySpeed = abs((nearestPlayer.yPos - obj.yPos) / 20.0f);
if (ySpeed > obj.var[kvMAXY]) ySpeed = obj.var[kvMAXY];
else if (ySpeed < obj.var[kvMINY]) ySpeed = obj.var[kvMINY];
obj.ySpeed = -ySpeed;
obj.state = STATE::JUMP;
obj.counter = obj.var[kvJUMPDELAY];
jjSample(obj.xPos, obj.yPos, ((jjRandom() & 1) == 0) ? SOUND::BUBBA_BUBBABOUNCE1 : SOUND::BUBBA_BUBBABOUNCE2);
} else
obj.direction = (obj.xPos > jjLocalPlayers[0].xPos) ? -1 : 1;
}
break;
case STATE::FREEZE:
if (obj.freeze > 0)
--obj.freeze;
if (obj.freeze <= 0) {
obj.state = obj.oldState;
obj.unfreeze(0);
}
break;
case STATE::JUMP:{
obj.yPos += (obj.ySpeed += obj.yAcc);
const int newXPos = int(obj.xPos + obj.xSpeed) + (width * obj.direction)/2;
if ((newXPos < 0) || (newXPos > jjLayerWidth[4]*32) || jjMaskedVLine(newXPos, int(obj.yPos - height/2), height)) {
obj.xSpeed = -obj.xSpeed;
obj.direction = -obj.direction;
}
obj.xPos += obj.xSpeed;
int newYPos = int(obj.yPos + obj.ySpeed);
if (obj.ySpeed < 0) {
if ((newYPos < 0) || jjMaskedHLine(int(obj.xPos) - width/2, width, newYPos - height/2)) {
obj.ySpeed = obj.yAcc;
obj.frameID = 2;
} else obj.frameID = 1;
}
if (obj.ySpeed > 0) {
if ((newYPos > jjLayerHeight[4]*32) || jjMaskedHLine(int(obj.xPos) - width/2, width, newYPos + height/2)) {
obj.state = STATE::IDLE;
obj.ySpeed = 0;
obj.frameID = 0;
Kangaroo::Private::putKangarooOnGround(obj, width, height);
} else obj.frameID = 2;
}
obj.determineCurFrame();
break;
} case STATE::DEACTIVATE:
obj.deactivate();
return;
case STATE::KILL:
obj.delete();
return;
}
obj.draw();
}
void Jill(jjOBJ@ obj) {
switch (obj.state) {
case STATE::START:
obj.state = STATE::DELAYEDSTART;
case STATE::DELAYEDSTART:
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ localPlayer = jjLocalPlayers[i];
if (localPlayer.bossActivated) {
localPlayer.boss = obj.objectID;
obj.state = STATE::START;
}
}
if (obj.state == STATE::START) {
obj.playerHandling = HANDLING::ENEMY;
break;
}
return;
case STATE::KILL:
if (obj.special >= 0) //textID
jjLocalPlayers[0].showText(obj.special, 0);
obj.playerHandling = HANDLING::DYING;
obj.state = STATE::DONE;
case STATE::DONE:
if (--obj.counterEnd == 0) {
obj.delete();
Kangaroo::Private::jillCallback(obj);
}
return;
default:
break;
}
int oldState = obj.state;
obj.behave(Joey, false);
obj.frameID = 0;
obj.determineCurFrame();
const int direction = obj.direction;
const bool secondStage = (obj.var[kvSECONDSTAGE] != 0 && obj.energy < 25);
if (secondStage) {
if (obj.var[kvSECONDSTAGE] == 1) {
obj.var[kvSECONDSTAGE] = 2;
obj.var[kvMINX] = 3;
obj.var[kvMAXX] = 5;
obj.var[kvJUMPDELAY] = 50;
obj.var[kvMINDISTANCE] = 600;
}
}
if (obj.doesHurt != 0 && (jjRandom() & 255) == 0) {
jjOBJ@ spawn = jjObjects[jjAddObject(obj.doesHurt, obj.xPos, obj.yPos + 11, obj.objectID, CREATOR::OBJECT, BEHAVIOR::INACTIVE)];
jjBEHAVIOR originalBehavior = jjObjectPresets[obj.doesHurt].behavior;
if (originalBehavior == Joey) {
spawn.direction = obj.direction;
spawn.xSpeed = spawn.direction * (1 + (jjRandom() & 3));
spawn.ySpeed = -6;
spawn.state = STATE::JUMP;
}
spawn.behavior = originalBehavior;
}
SPRITE::Mode mode = SPRITE::NORMAL;
uint8 param = 15;
SPRITE::Mode modeDark = SPRITE::BRIGHTNESS;
uint8 paramDark = 96;
if (obj.justHit != 0) {
mode = modeDark = SPRITE::SINGLECOLOR;
paramDark = param;
const int nearestPlayerID = obj.findNearestPlayer(64);
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ localPlayer = jjLocalPlayers[i];
if (localPlayer.specialMove != 0) {
localPlayer.specialMove = 0;
localPlayer.ySpeed -= 1;
localPlayer.extendInvincibility(-35);
}
}
} else if (obj.state == STATE::FREEZE) {
mode = modeDark = SPRITE::FROZEN;
} else if (secondStage) {
mode = modeDark = SPRITE::TINTED;
param = 25;
paramDark = 29;
}
int armAngle = obj.age;
if (obj.state != STATE::FREEZE) {
const int nearestPlayerID = obj.findNearestPlayer(1000000);
if (nearestPlayerID >= 0) {
jjPLAYER@ nearestPlayer = jjPlayers[nearestPlayerID];
const float deltaX = nearestPlayer.xPos - obj.xPos;
const float deltaY = nearestPlayer.yPos - obj.yPos;
armAngle = int(atan2(
(direction == 1) ? deltaY : -deltaY,
abs(deltaX)
) * -512.0 * 0.318309886142228);
}
obj.age = armAngle;
}
const float armSin = jjSin(armAngle);
const float armCos = jjCos(armAngle);
int tailAngle = int(obj.ySpeed*-16)*direction;
const int tailX = int(obj.xPos) - 32 * direction;
const int tailY = int(obj.yPos) + 23;
const int gloveLength = (12 + 29 + 29) * obj.direction;
const int legAngle = int(obj.ySpeed*8)*direction;
const int arm1X = int(obj.xPos) - 2 * direction;
const int arm1Y = int(obj.yPos) - 7;
const int arm2X = int(obj.xPos) + 4 * direction;
const int arm2Y = int(obj.yPos - 11);
//if (tailAngle > 0) tailAngle = 0;
if (obj.ySpeed < 0) {
obj.animSpeed = jjSampleLooped(obj.xPos, obj.yPos, SOUND::COMMON_FLAMER, obj.animSpeed);
if (obj.state != STATE::FREEZE && (jjRandom() & 1) == 0) {
jjPARTICLE@ part = jjAddParticle(PARTICLE::FIRE);
if (part !is null) {
part.xSpeed = jjSin(tailAngle) * 2;
part.ySpeed = jjCos(tailAngle) * 2;
part.xPos = tailX + part.xSpeed * 8;
part.yPos = tailY + part.ySpeed * 8;
part.xSpeed += abs(obj.xSpeed) * -obj.direction;
}
}
if (oldState == STATE::IDLE) {
obj.var[kvGLOVE1FRAME] = 1;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PISTOL1);
obj.var[kvGLOVE2FRAME] = 0;
}
}
{
int oldGloveFrame = obj.var[kvGLOVE1FRAME];
if (oldGloveFrame > 0 && oldGloveFrame < 12 && (jjGameTicks & 3) == 1)
obj.var[kvGLOVE1FRAME] = oldGloveFrame + 1;
oldGloveFrame = obj.var[kvGLOVE2FRAME];
if (obj.state == STATE::IDLE && oldGloveFrame == 0) {
obj.var[kvGLOVE2FRAME] = 1;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PISTOL1);
}
if (oldGloveFrame > 0 && oldGloveFrame < 12 && (jjGameTicks & 3) == 1)
obj.var[kvGLOVE2FRAME] = oldGloveFrame + 1;
}
const int glove2FrameID = Kangaroo::Private::firstGloveAnimationFrame + (obj.var[kvGLOVE2FRAME] + 3) % 12;
jjDrawRotatedSpriteFromCurFrame(
arm2X + 12*armSin + gloveLength*armCos,
arm2Y + 12*armCos - gloveLength*armSin,
glove2FrameID,
armAngle - 256 * obj.direction,
direction, 2, modeDark, paramDark
); //glove
if (obj.state != STATE::FREEZE) {
const int glove2Length = gloveLength + (jjAnimFrames[glove2FrameID].height - 30) * 2 * obj.direction;
Kangaroo::Private::doGloveAt(
int(arm2X + 12*armSin + glove2Length*armCos),
int(arm2Y + 12*armCos - glove2Length*armSin)
);
}
jjDrawRotatedSpriteFromCurFrame(arm2X, arm2Y, obj.curFrame + 1, armAngle, direction, 1, modeDark, paramDark); //back arm
jjDrawRotatedSpriteFromCurFrame(obj.xPos - 24 * direction, obj.yPos + 24, obj.curFrame + 2, legAngle, direction, 1, modeDark, paramDark); //back leg
jjDrawRotatedSpriteFromCurFrame(tailX, tailY, obj.curFrame + 3, tailAngle, direction, 1, mode, param); //tail
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, direction, mode, param); //body
jjDrawRotatedSpriteFromCurFrame(obj.xPos - 30 * direction, obj.yPos + 28, obj.curFrame + 2, legAngle, direction, 1, mode, param); //leg
jjDrawRotatedSpriteFromCurFrame(arm1X, arm1Y, obj.curFrame + 1, armAngle, direction, 1, mode, param); //arm
const int glove1FrameID = Kangaroo::Private::firstGloveAnimationFrame + (obj.var[kvGLOVE1FRAME] + 3) % 12;
jjDrawRotatedSpriteFromCurFrame(
arm1X + 12*armSin + gloveLength*armCos,
arm1Y + 12*armCos - gloveLength*armSin,
glove1FrameID,
armAngle - 256 * obj.direction,
direction, 2, mode, param
); //glove
if (obj.state != STATE::FREEZE) {
const int glove1Length = gloveLength + (jjAnimFrames[glove1FrameID].height - 30) * 2 * obj.direction;
Kangaroo::Private::doGloveAt(
int(arm2X + 12*armSin + glove1Length*armCos),
int(arm2Y + 12*armCos - glove1Length*armSin)
);
}
}
}
bool onDrawHealth(jjPLAYER@ player, jjCANVAS@ canvas) {
canvas.drawString(30, 585, formatInt(exit%7, "1") + "/6", STRING::SMALL, STRING::NORMAL);
canvas.drawSprite(20, 585, ANIM::PICKUPS, 11, jjGameTicks>>2, -1, SPRITE::NORMAL);
canvas.drawString(100, 585, formatInt(frogexit%5, "1") + "/4", STRING::SMALL, STRING::NORMAL);
canvas.drawResizedSprite(90, 585, ANIM::PICKUPS, 52, 4,0.7, 0.7, SPRITE::NORMAL);
return false;
}
bool onDrawLives(jjPLAYER@ player, jjCANVAS@ canvas) { return true;}
void onLevelReload() {
if(crate2 == true)
{jjAddObject(OBJECT::TNT, 1*32, 35*32);}
if(crate3 == true)
{jjAddObject(OBJECT::TNT, 49*32, 12*32);}
if(crate5 == true)
{jjAddObject(OBJECT::TNT, 208*32, 48*32);}
if(crate6 == true)
{jjAddObject(OBJECT::TNT, 250*32, 14*32);}
jjEnabledASFunctions[3] = true;
jjEnabledASFunctions[2] = true;
jjMusicLoad("mo4a_The Golden City.ogg");
gem::restorePlayerGems();
jjLocalPlayers[0].lives++;
jjWaterLighting = WATERLIGHT::GLOBAL;
for (uint i = 0; i < 32; ++i)
jjTriggers[i] = SavedTriggers[i];
}
array<bool> SavedTriggers(32, false);
//Extendable Checkpoints by VioletCLM
void CheckpointWrapper(jjOBJ@ obj) {
if (obj.state == STATE::STOP) { //don't do anything anymore
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, 8);
} else if (obj.state == STATE::DEACTIVATE) { //due to death
obj.deactivate();
} else {
obj.behave(BEHAVIOR::CHECKPOINT);
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, 8);
if (obj.state == STATE::DONE) { //triggered by the player hitting it
obj.state = STATE::STOP;
//save the current state of some properties
for (uint i = 0; i < 32; ++i)
SavedTriggers[i] = jjTriggers[i];
//OPTIONAL: this loop makes checkpoints reusable, so only the most recent checkpoint you touched is ever active
for (int i = jjObjectCount; --i > 0;) {
jjOBJ@ obj2 = jjObjects[i];
if (obj2.eventID == OBJECT::CHECKPOINT && i != obj.objectID && obj2.isActive) {
obj2.state = STATE::SLEEP;
obj2.var[0] = 0;
}
}
}
}
}
jjTEXTAPPEARANCE SignTextAppearance = STRING::NORMAL;
class Sign {
private int xPos, yPos; //These pixel-based positions will be generated from tile-based positions in the constructor by multiplying by 32
private string text;
private uint widthOfText;
Sign(){} //AngelScript requires any class that appears in any array to have an explicit default constructor, even if it's never called
Sign(int xTile, int yTile, const string &in t) {
xPos = xTile * 32; //Since this is a constant operation, it could strictly be performed in the draw method instead of the constructor, but this way involves fewer multiplication instructions
yPos = yTile * 32; //
text = t;
SignTextAppearance.newline = STRING::SPECIALSIGN; //Causes the drawString method to interpret instances of the \n character as signals to drop down to a new line, similar to the special effect of the @ character in the STRING::SPIN appearance.
SignTextAppearance.spacing = -2; //int jjTEXTAPPEARANCE::spacing is new in 5.2, and this particular value is equivalent to prefixing the string with "ยง2". Make sure to check out bool jjTEXTAPPEARANCE::monospace too, though it didn't end up getting used in this level.
widthOfText = jjGetStringWidth(text, STRING::SMALL, SignTextAppearance); //Used for determining how large of a dark rectangle should be drawn behind the text. A matching heightOfText value could of course be generated by counting the number of newline characters--for example, "heightOfText = text.split("\n").length * 20;"--but here the rectangles are constant height instead to limit the temptation to ramble on and on.
}
void draw(jjCANVAS@ layer, uint8 textIntensity) const { //Because this method will be called from an onDraw method, it's important to have a jjCANVAS@ passed among the arguments.
layer.drawRectangle(xPos, yPos - 16, widthOfText + 8, 55, 0, SPRITE::TRANSLUCENT);
layer.drawString(xPos, yPos, text, STRING::SMALL, SignTextAppearance, 0, SPRITE::BLEND_HARDLIGHT, textIntensity);
}
}
const array<Sign> Signs = {
Sign(54, 38, "Rabbits cannot swim.\nHow about frogs?"),
Sign(100, 56, "HEY! GET ME OUTTA HERE\nWITH THAT KEY OVER THERE!"),
};
void onDrawLayer3(jjPLAYER@, jjCANVAS@ layer) {
if((jjKey[0x54] && p.charCurr == CHAR::FROG)||(p.charCurr == CHAR::FROG && p.xPos >90*32 && p.xPos<113*32 && p.yPos>34*32)){
const uint8 textIntensity = 200 + int(jjSin(jjGameTicks * 16) * 50);
for (uint signID = 0; signID < Signs.length; ++signID)
Signs[signID].draw(layer, textIntensity);
}
}
bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
return MLLE::WeaponHook.drawAmmo(player, canvas);
}
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.