Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Lori Fortress | Primpy | Single player | 8.7 |
const bool MLLESetupSuccessful = MLLE::Setup(); ///@MLLE-Generated
#include "MLLE-Include-1.6.asc" ///@MLLE-Generated
#pragma require "primpLoriFortress-MLLE-Data-3.j2l" ///@MLLE-Generated
#pragma require "primpLoriFortress-MLLE-Data-2.j2l" ///@MLLE-Generated
#pragma require "primpLoriFortress-MLLE-Data-1.j2l" ///@MLLE-Generated
#pragma require "primpLoriFortress.j2l" ///@MLLE-Generated
#pragma require "Meteor.j2a"
#pragma require "CosmicDust.j2a"
#pragma require "Mortar.j2a"
#pragma require "Lightningrod.j2a"
#pragma require "CloneMachine.j2a"
#pragma require "expmine.wav"
#pragma require "lowind.wav"
#pragma require "f_gren4.wav"
#pragma require "ZAPFIZZ1.wav"
#pragma require "ZAPFIZZ2.wav"
#pragma require "kaze_loop.ogg"
#pragma require "fireeye.ogg"
#include "ArcaneWeapon2.asc"
#include "ArcaneWeapon3.asc"
#include "ArcaneWeapon4.asc"
#include "ArcaneWeapon7.asc"
#include "ArcaneWeapon8.asc"
#include "LFgems.asc"
CosmicDust Duster();
uint FriendColor(uint8 a, uint8 b, uint8 c, uint8 d) { return a | (b << 8) | (c << 16) | (d << 24); }
uint8 loriCounter = 0;
bool bossDefeated = false, bossStarted = false;
void onLevelLoad()
{
jjPLAYER@ Player = jjLocalPlayers[0];
Player.morphTo(Player.charOrig = CHAR::LORI, false);
jjAnimSets[ANIM::CUSTOM[22]].load(0, "Meteor.j2a");
jjAnimSets[ANIM::CUSTOM[23]].load(0, "CosmicDust.j2a");
jjAnimSets[ANIM::CUSTOM[24]].load(0, "Mortar.j2a");
jjAnimSets[ANIM::CUSTOM[27]].load(0, "Lightningrod.j2a");
jjAnimSets[ANIM::CUSTOM[28]].load(0, "CloneMachine.j2a");
Foo(jjObjectPresets[OBJECT::MORPH]);
CloneMachine(jjObjectPresets[OBJECT::ROBOT]);
jjPlayers[28].fur = FriendColor(64,24,64,72);
}
void onMain() {
gem::deleteCollectedGems();
jjDrawSprite(1083.646, 4012.51, ANIM::JAZZ, RABBIT::CORPSE, 0, 0, SPRITE::NORMAL);
jjDrawSprite(1597.939, 4072.51, ANIM::SPAZ, RABBIT::CORPSE, 0, 0, SPRITE::NORMAL);
if (jjTriggers[1] == true && bossStarted == false) {
jjDrawSpriteFromCurFrame(5007, 387, jjAnimations[jjAnimSets[ANIM::CUSTOM[28]]].firstFrame + 2, 0, SPRITE::NORMAL);
}
}
void onPlayer(jjPLAYER@ play)
{
gem::trackPlayerGems(play);
gem::upgradeHealth(play);
}
void onLevelReload()
{
gem::restorePlayerGems();
jjLocalPlayers[0].lives++;
loriCounter = 0;
bossDefeated = false;
bossStarted = false;
jjMusicLoad("kaze_loop.ogg");
CloneMachine(jjObjectPresets[OBJECT::ROBOT]);
}
bool onDrawLives(jjPLAYER@ play, jjCANVAS@ canvas) { return true; }
enum FooWeapon { None, Meteor, Duster, Mortar, Rod, Sanguine };
bool FooSoundsLoaded = false;
array<MLLEWeapons::WeaponInterface@> ArcaneWeapons = {null, ArcaneWeapons::MeteorGun::Weapon(), ArcaneWeapons::CosmicDuster::Weapon(), ArcaneWeapons::MortarLauncher::Weapon(), ArcaneWeapons::LightningRod::Weapon(), ArcaneWeapons::SanguineSpear::Weapon()};
class Foo : jjBEHAVIORINTERFACE {
Foo(jjOBJ@ preset) {
preset.behavior = this;
preset.playerHandling = HANDLING::ENEMY;
preset.scriptedCollisions = true;
preset.bulletHandling = HANDLING::HURTBYBULLET;
preset.isTarget = true;
preset.isFreezable = true;
preset.isBlastable = false;
preset.energy = 88; // 3 + 45 buffer (Lori does an absurd amount of damage with her special kick, just making sure...)
preset.determineCurAnim(ANIM::LORI, RABBIT::STAND);
preset.determineCurFrame();
preset.direction = -1;
preset.triggersTNT = false;
}
void onBehave(jjOBJ@ obj) override {
uint frameID;
const auto lastCurFrame = obj.curFrame;
jjPLAYER@ Player = jjLocalPlayers[0];
uint loriHurtFreq;
const auto@ anim = jjAnimations[jjAnimSets[obj.special] + obj.curAnim];
if ( (obj.energy <= 85 || bossDefeated == true) && obj.state != STATE::EXTRA) {
obj.frameID = 0;
obj.bulletHandling = HANDLING::IGNOREBULLET;
obj.playerHandling = HANDLING::DYING;
obj.isTarget = false;
obj.isFreezable = false;
obj.state = STATE::EXTRA;
}
switch (obj.state) {
case STATE::START: {
if (!FooSoundsLoaded) {
FooSoundsLoaded = true;
jjSampleLoad(SOUND::ORANGE_BOEMR, "expmine.wav");
jjSampleLoad(SOUND::ORANGE_BOEML, "lowind.wav");
jjSampleLoad(SOUND::ORANGE_MERGE, "f_gren4.wav");
jjSampleLoad(SOUND::COMMON_ELECTRICHIT, "ZAPFIZZ1.wav");
jjSampleLoad(SOUND::COMMON_ELECTRIC2, "ZAPFIZZ2.wav");
}
obj.special = ANIM::LORI;
switch (obj.doesHurt = (getParameterAtOrigin(obj, 0, 3) % 6)) { //weapon
case FooWeapon::Meteor:
obj.state = STATE::BOUNCE;
obj.curAnim = RABBIT::JUMPFIRERIGHT;
break;
case FooWeapon::Duster:
obj.state = STATE::JUMP;
obj.curAnim = RABBIT::JUMPFIRERIGHT;
break;
case FooWeapon::Mortar:
obj.state = STATE::ATTACK;
obj.curAnim = RABBIT::DIVEFIRERIGHT;
obj.counter = jjRandom();
break;
case FooWeapon::Rod:
obj.state = STATE::FLY;
obj.curAnim = RABBIT::AIRBOARD;
break;
case FooWeapon::Sanguine:
default:
obj.state = STATE::WALK;
break;
}
if (obj.doesHurt != FooWeapon::Rod)
obj.putOnGround(true);
break; }
case STATE::BOUNCE: //Meteor
if (obj.counter == 0) //starting out
obj.yAcc = obj.yPos;
obj.yPos = obj.yAcc - abs(jjSin(obj.counter += 8) * 128);
if (obj.counter & 511 == 0) {
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_JUMP);
jjObjects[jjAddObject(OBJECT::EXPLOSION, obj.xPos, obj.yPos + 12)].determineCurAnim(ANIM::AMMO, 72);
} else if (obj.counter & 511 == 256) {
jjOBJ@ meteor = fireBullet(obj, lastCurFrame, OBJECT::BOUNCERBULLET);
jjSample(meteor.xPos, meteor.yPos, SOUND::ORANGE_BOEMR, 42, 20000);
meteor.determineCurAnim(ANIM::CUSTOM[22], 1);
meteor.ySpeed = 0;
meteor.killAnim = jjObjectPresets[OBJECT::SEEKERBULLET].killAnim;
meteor.lightType = LIGHT::POINT;
meteor.light = 10;
meteor.xSpeed = abs(meteor.xSpeed);
meteor.xAcc = abs(meteor.xAcc);
meteor.behavior = Meteor;
}
obj.direction = (obj.xPos < Player.xPos) ? 1 : -1;
frameID = obj.counter >> 6;
break;
case STATE::JUMP: //Duster
if (obj.ySpeed < 0 && jjMaskedPixel(int(obj.xPos), int(obj.yPos + obj.ySpeed) - 12))
obj.ySpeed = 0;
else
obj.yPos += obj.ySpeed += 0.25;
if (jjMaskedPixel(int(obj.xPos), int(obj.yPos) + 12)) {
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_JUMP);
jjObjects[jjAddObject(OBJECT::EXPLOSION, obj.xPos, obj.yPos + 12)].determineCurAnim(ANIM::AMMO, 72);
obj.ySpeed = -8;
} else {
const float targetX = obj.xPos + obj.direction * 1.25 * (89 - obj.energy);
if (jjMaskedVLine(int(targetX), int(obj.yPos) - 12, 24))
obj.direction = -obj.direction;
else
obj.xPos = targetX;
}
if (++obj.counter % 50 == 1) {
jjOBJ@ duster = fireBullet(obj, lastCurFrame, OBJECT::ICEBULLET);
duster.determineCurAnim(ANIM::CUSTOM[23], 1);
duster.counterEnd = 180;
duster.lightType = LIGHT::BRIGHT;
duster.light = 8;
duster.playerHandling = HANDLING::PICKUP;
duster.scriptedCollisions = true;
duster.behavior = Duster;
}
obj.var[1] = jjSampleLooped(obj.xPos,obj.yPos,SOUND::ORANGE_BOEML,obj.var[1]);
frameID = obj.counter >> 6;
break;
case STATE::ATTACK: //Mortar
if (++obj.counter & (obj.creatorType == CREATOR::LEVEL ? 63 : 127) == 5) {
jjOBJ@ mortar = fireBullet(obj, lastCurFrame, OBJECT::SEEKERBULLET);
jjSample(mortar.xPos, mortar.yPos, SOUND::ORANGE_MERGE, 0, 0);
mortar.determineCurAnim(ANIM::CUSTOM[22], 1);
mortar.xSpeed = 7;
mortar.xAcc = abs(mortar.xAcc);
mortar.ySpeed = -9 + (jjRandom() & ((4 << (88 - obj.energy)) - 1)) / 2.f;
mortar.counterEnd = 90;
mortar.behavior = Mortar;
}
obj.direction = (obj.xPos < Player.xPos) ? 1 : -1;
frameID = obj.counter >> 6;
break;
case STATE::FLY: //Rod
obj.xPos = obj.xOrg + jjSin((++obj.counterEnd) << 2) * 100;
obj.yPos = obj.yOrg + 8 * (1 - jjSin(jjGameTicks * 12));
obj.direction = (((obj.counterEnd + 64) & 255) < 128) ? 1 : -1;
if (obj.counterEnd & 127 == 64) {
obj.var[0] = 22;
obj.curAnim = RABBIT::AIRBOARDTURN;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_AIRBTURN, 100, 16537);
}
if (obj.var[0] != 0) {
if ((obj.var[0] = obj.var[0] - 1) == 0) {
obj.curAnim = RABBIT::AIRBOARD;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_AIRBTURN2, 0, 16537);
} else
frameID = obj.var[0] / 3;
}
if (obj.var[0] == 0) { //not turning
frameID = obj.counterEnd >> 3;
if (obj.age < -60 && (obj.energy < 88 || (Player.yPos > obj.yPos && abs(Player.xPos - obj.xPos) < 50)) && !jjMaskedHLine(int(obj.xPos) - 5, 10, int(obj.yPos))) {
jjOBJ@ rod = fireBullet(obj, lastCurFrame, OBJECT::TNT);
jjSample(rod.xPos, rod.yPos, SOUND::COMMON_MONITOR, 0, 12500);
rod.determineCurAnim(ANIM::CUSTOM[27], 0);
rod.playerHandling = HANDLING::PARTICLE;
rod.bulletHandling = HANDLING::IGNOREBULLET;
rod.counterEnd = 255;
rod.var[4] = 1; //color
rod.behavior = Lightningrod;
}
}
obj.var[1] = jjSampleLooped(obj.xPos,obj.yPos,SOUND::COMMON_AIRBOARD,obj.var[1]);
break;
case STATE::WALK: //Sanguine/None
obj.xSpeed = (89 - obj.energy) * 1.5 * obj.direction;
obj.behave(BEHAVIOR::WALKINGENEMY, false);
if (obj.doesHurt == FooWeapon::Sanguine) {
if (obj.counter % 70 == 10) {
for (uint i = obj.energy; i < 89; ++i) {
jjOBJ@ spear = fireBullet(obj, lastCurFrame, OBJECT::FIREBALLBULLET);
jjSample(spear.xPos, spear.yPos, SOUND::HATTER_PTOEI, 0, 20000);
spear.xSpeed = abs(obj.xSpeed) * 4;
spear.xAcc = abs(spear.xAcc);
spear.ySpeed = -2;
spear.counterEnd = 95;
spear.var[6] = 8;
spear.behavior = BloodSpear;
if (obj.energy != 88 && i == 88)
spear.ySpeed *= 2;
else if (i == 87)
spear.ySpeed = 0;
}
}
}
if (obj.energy == 88) obj.curAnim = RABBIT::RUN1;
else obj.curAnim = RABBIT::RUN2 + (87 - obj.energy);
frameID = ++obj.counter / int(10 - abs(obj.xSpeed));
break;
case STATE::EXTRA: //dying
if (obj.justHit == 1 || bossDefeated == true) {
if (Player.bossActivated == true && loriCounter != 0)
loriCounter--;
obj.curAnim = RABBIT::DIE;
loriHurtFreq = jjRandom()%3;
if (bossDefeated == false) {
jjSample(obj.xPos, obj.yPos, SOUND::LORISOUNDS_DIE1, 0, (loriHurtFreq == 0) ? 35000 : (loriHurtFreq == 1) ? 30000 : 25000);
jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_SHOOT); } }
if (not ((jjMaskedPixel(int(obj.xPos), int(obj.yPos)+22)) or (jjMaskedPixel(int(obj.xPos)+11, int(obj.yPos)+22)) or (jjMaskedPixel(int(obj.xPos)-11, int(obj.yPos)+22))))
obj.yPos = obj.yPos + 2 + ((obj.curAnim == RABBIT::CORPSE) ? 23 : (obj.frameID * 2));
if (uint(obj.frameID) < 23) {
if (jjGameTicks % 7 == 0) obj.frameID++; }
else {
obj.curAnim = RABBIT::CORPSE;
//obj.delete();
return;
}
break;
default: //deactivate/freeze/done
obj.behave(BEHAVIOR::TUBETURTLE, false);
return;
}
if (obj.justHit == 1 && obj.energy > 85) {
uint loriHurt = jjRandom()%8;
loriHurtFreq = jjRandom()%3;
switch (loriHurtFreq) {
case 0: loriHurtFreq = 35000; break;
case 1: loriHurtFreq = 30000; break;
case 2: loriHurtFreq = 25000; break;
}
switch (loriHurt) {
case 0:
jjSample(obj.xPos, obj.yPos, SOUND::LORISOUNDS_HURT0, 0, loriHurtFreq);
jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_HYDRO, 40);
break;
case 1:
jjSample(obj.xPos, obj.yPos, SOUND::LORISOUNDS_HURT1, 0, loriHurtFreq);
jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_HYDRO2, 40);
break;
case 2:
jjSample(obj.xPos, obj.yPos, SOUND::LORISOUNDS_HURT2, 0, loriHurtFreq);
jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_HYDROFIL, 40);
break;
case 3:
jjSample(obj.xPos, obj.yPos, SOUND::LORISOUNDS_HURT3, 0, loriHurtFreq);
jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_HYDRO, 40);
break;
case 4:
jjSample(obj.xPos, obj.yPos, SOUND::LORISOUNDS_HURT4, 0, loriHurtFreq);
jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_HYDRO2, 40);
break;
case 5:
jjSample(obj.xPos, obj.yPos, SOUND::LORISOUNDS_HURT5, 0, loriHurtFreq);
jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_HYDROFIL, 40);
break;
case 6:
jjSample(obj.xPos, obj.yPos, SOUND::LORISOUNDS_HURT6, 0, loriHurtFreq);
jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_HYDRO, 40);
break;
case 7:
jjSample(obj.xPos, obj.yPos, SOUND::LORISOUNDS_HURT7, 0, loriHurtFreq);
jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_HYDROFIL, 40);
break;
}
}
if (obj.state != STATE::EXTRA)
obj.curFrame = anim.firstFrame + (frameID % anim.frameCount); // hell if I know what was Violet doing with frameID...
else obj.curFrame = anim.firstFrame + (obj.frameID % anim.frameCount);
}
jjOBJ@ fireBullet(jjOBJ@ obj, int lastCurFrame, OBJECT::Object eventID) const {
obj.age = 5;
obj.curFrame = lastCurFrame; //for gunspot, etc.
jjOBJ@ bullet = jjObjects[obj.fireBullet(eventID)];
bullet.playerHandling = HANDLING::ENEMYBULLET;
bullet.animSpeed = 1;
return bullet;
}
void onDraw(jjOBJ@ obj) {
const SPRITE::Mode mode = obj.state == STATE::FREEZE ? SPRITE::FROZEN : obj.justHit == 0 ? SPRITE::PLAYER : SPRITE::SINGLECOLOR;
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, mode, 28);
if (obj.state == STATE::DONE)
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::TRANSLUCENTCOLOR, 28); //got to do it this way, because TINTED would erase the player colors and make it look like jazz instead of purplejazz
else if (obj.age-- > 0) { //flare time
const jjANIMFRAME@ frame = jjAnimFrames[obj.curFrame];
jjDrawSprite(obj.xPos + (frame.hotSpotX - frame.gunSpotX) * obj.direction, obj.yPos + frame.hotSpotY - frame.gunSpotY, ANIM::AMMO, 16, 0, obj.direction, SPRITE::PLAYER, 28); //flare
}
}
}
int getParameterAtOrigin(const jjOBJ@ obj, int offset, int length) /*const*/ {
return jjParameterGet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, offset, length);
}
void Meteor(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BULLET, obj.state == STATE::EXPLODE? true:false);
if (obj.state != STATE::EXPLODE) {
obj.var[2] = 0;
obj.age += obj.direction == 0? 10 : 10 * obj.direction;
jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[22], obj.eventID == OBJECT::BOUNCERBULLET? 1:0, 0, -obj.age, 1, 1, obj.eventID == OBJECT::BOUNCERBULLET || obj.var[4] == 1? SPRITE::SINGLEHUE : SPRITE::NORMAL, 72);
jjPARTICLE@ smoke = jjAddParticle(PARTICLE::SMOKE);
if (smoke !is null) {
smoke.xPos = smoke.xPos;
smoke.yPos = smoke.yPos;
}
if (obj.eventID == OBJECT::BOUNCERBULLETPU && obj.var[4] == 0) {
jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[22], 0, 0, -obj.age, 1, 1, SPRITE::TRANSLUCENTSINGLEHUE, 40);
jjPARTICLE@ cinders = jjAddParticle(PARTICLE::FIRE);
if (cinders !is null) {
cinders.xPos = int(obj.xPos - 8) + jjRandom()%17;
cinders.yPos = int(obj.yPos - 8) + jjRandom()%17;
}
}
if (obj.yPos > jjWaterLevel) {
obj.var[4] = 1;
obj.xSpeed = obj.xSpeed * 0.875;
obj.ySpeed = obj.ySpeed * 0.875;
}
switch (obj.direction) {
case 1: obj.xSpeed -= obj.eventID == OBJECT::BOUNCERBULLET? 0.1:0.15; obj.ySpeed += obj.eventID == OBJECT::BOUNCERBULLET? 0.15:0.2; break;
case -1: obj.xSpeed += obj.eventID == OBJECT::BOUNCERBULLET? 0.1:0.15; obj.ySpeed += obj.eventID == OBJECT::BOUNCERBULLET? 0.15:0.2; break;
}
if (obj.xSpeed == 0) obj.ySpeed += 0.4;
if (obj.ySpeed > 8) obj.ySpeed = 8;
} else {
obj.age = 0;
if (obj.var[2] == 0) {
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BENZIN1, 0, 0);
obj.var[2] = 1;
if (obj.eventID == OBJECT::BOUNCERBULLETPU) {
for (int i = -1; i <= 1; i+= 2) {
jjOBJ@ rock = jjObjects[jjAddObject(OBJECT::SHARD, int(obj.xPos + (i * 12)), int(obj.yPos - 8), obj.creatorID, CREATOR::OBJECT, Rock)];
rock.determineCurAnim(ANIM::CUSTOM[22], 1);
rock.playerHandling = HANDLING::ENEMYBULLET;
rock.var[3] = 2;
rock.var[4] = obj.var[4];
rock.var[6] = 8;
rock.animSpeed = 1;
rock.direction = i;
rock.xSpeed = 6 * i;
rock.ySpeed = -3;
rock.state = STATE::FLY;
rock.lightType = LIGHT::POINT;
rock.light = 10;
rock.counterEnd = jjObjectPresets[OBJECT::BOUNCERBULLET].counterEnd;
rock.killAnim = jjObjectPresets[OBJECT::BOUNCERBULLET].killAnim;
}
}
}
}
}
void Rock(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BULLET, obj.state == STATE::EXPLODE? true:false);
if (obj.state == STATE::FLY) {
obj.age += obj.direction == 0? 10 : 10 * obj.direction;
jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[22], 1, 0, -obj.age, 1, 1, obj.var[4] == 1? SPRITE::SINGLEHUE : SPRITE::NORMAL, 72);
switch (obj.direction) {
case 1: obj.xSpeed -= 0.05; obj.ySpeed += 0.1; break;
case -1: obj.xSpeed += 0.05; obj.ySpeed += 0.1; break;
}
if (obj.yPos > jjWaterLevel) {
obj.var[4] = 1;
obj.xSpeed = obj.xSpeed * 0.875;
obj.ySpeed = obj.ySpeed * 0.875;
}
jjPARTICLE@ smoke = jjAddParticle(PARTICLE::SMOKE);
if (smoke !is null) {
smoke.xPos = obj.xPos;
smoke.yPos = obj.yPos;
}
}
}
class CosmicDust : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
const jjOBJ@ creator = jjObjects[obj.creatorID];
if (creator.eventID != OBJECT::MORPH) { //ded
obj.delete();
return;
}
obj.behave(obj.state == STATE::EXPLODE? BEHAVIOR::BULLET : BEHAVIOR::TNT, false);
obj.var[0] = obj.var[0] + (5 * obj.direction);
if (obj.state != STATE::EXPLODE) {
obj.xPos = creator.xPos + (obj.eventID == OBJECT::ICEBULLETPU? 160:120)*jjSin((obj.counter + 1)*12) * (obj.direction != 0? obj.direction : 1);
obj.yPos = creator.yPos - (obj.eventID == OBJECT::ICEBULLETPU? 80:60)*jjCos((obj.counter + 1)*12);
} else {
obj.delete();
}
}
void onDraw(jjOBJ@ obj) {
if (obj.state != STATE::EXPLODE && obj.counter > 1) {
jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[23], obj.eventID == OBJECT::ICEBULLETPU? 0:1, 0, -obj.var[0], 1, 1, SPRITE::ALPHAMAP, obj.eventID == OBJECT::ICEBULLETPU? 34:72);
jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[23], obj.eventID == OBJECT::ICEBULLETPU? 0:1, 0, -obj.var[0], 1, 1, SPRITE::ALPHAMAP, obj.eventID == OBJECT::ICEBULLETPU? 34:72);
}
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
player.frozen = obj.freeze;
obj.delete();
return true;
}
}
void Mortar(jjOBJ@ obj) {
obj.behave(obj.state == STATE::EXPLODE? BEHAVIOR::RFBULLET : BEHAVIOR::BULLET, false);
if (obj.yPos <= 0) obj.state = STATE::EXPLODE;
obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
switch (obj.state) {
case STATE::START:
obj.state = STATE::FLY;
obj.lightType = LIGHT::POINT;
obj.var[2] = 0;
break;
case STATE::FLY:
jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[24], obj.eventID == OBJECT::SEEKERBULLETPU? 2:0, jjGameTicks >> 2, obj.var[0], 0.75, 0.75, SPRITE::NORMAL);
if (obj.counter % 5 == 0 && !jjLowDetail) {
jjOBJ@ trail = jjObjects[jjAddObject(OBJECT::EXPLOSION, int(obj.xPos - jjCos(obj.var[0])), int(obj.yPos - jjSin(obj.var[0])))];
trail.determineCurAnim(ANIM::AMMO, 3);
trail.lightType = LIGHT::NONE;
trail.playerHandling = HANDLING::PARTICLE;
trail.bulletHandling = HANDLING::IGNOREBULLET;
trail.isBlastable = false;
}
switch (obj.direction) {
case 1: obj.xSpeed -= 0.275; obj.ySpeed += 0.225; break;
case -1: obj.xSpeed += 0.275; obj.ySpeed += 0.225; break;
}
if (obj.xSpeed == 0) obj.ySpeed += 0.3;
if (obj.ySpeed > 12) obj.ySpeed = 12;
break;
case STATE::EXPLODE:
jjDrawResizedSprite(obj.xPos, obj.yPos, ANIM::AMMO, 5, obj.curFrame + 5, 2, 2, SPRITE::NORMAL);
if (obj.var[2] == 0) {
jjOBJ@ blast = jjObjects[jjAddObject(OBJECT::BULLET, obj.xPos, obj.yPos, obj.creatorID, CREATOR::OBJECT, MortarShockwave)];
obj.var[2] = 1;
blast.var[2] = 1;
blast.animSpeed = obj.animSpeed;
}
break;
}
}
void MortarShockwave(jjOBJ@ obj) {
obj.playerHandling = HANDLING::PARTICLE;
obj.bulletHandling = HANDLING::IGNOREBULLET;
if (obj.var[2] == 1) {
obj.lightType = obj.var[2] == 1? LIGHT::RING2 : LIGHT::NONE;
obj.var[1] = obj.var[1] + 1;
obj.light += 2;
obj.var[4] = obj.light * 4;
jjPLAYER@ player = jjLocalPlayers[0];
float dx = player.xPos - obj.xPos, dy = player.yPos - obj.yPos;
if (dx * dx + dy * dy < obj.var[4] * obj.var[4])
player.hurt(obj.animSpeed);
}
if (obj.var[1] == 14) {
obj.var[1] = 0;
obj.var[2] = 0;
obj.var[4] = 0;
obj.delete();
}
}
void BloodSpear(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BULLET, false);
obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
if (obj.state == STATE::FLY) {
jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::HATTER, 3, jjGameTicks >> 2, obj.var[0], 2, 1, SPRITE::SINGLEHUE, obj.eventID == OBJECT::FIREBALLBULLETPU? 15:24);
switch (obj.direction) {
case 1: obj.xSpeed -= 0.1; obj.ySpeed += 0.1; break;
case -1: obj.xSpeed += 0.1; obj.ySpeed += 0.1; break;
}
if (obj.xSpeed == 0) obj.ySpeed += 0.15;
jjPARTICLE@ blood = jjAddParticle(PARTICLE::ICETRAIL);
blood.xPos = obj.xPos;
blood.yPos = obj.yPos;
blood.icetrail.color = obj.eventID == OBJECT::FIREBALLBULLETPU? 16:24;
blood.icetrail.colorStop = obj.eventID == OBJECT::FIREBALLBULLETPU? 24:32;
}
if (obj.state == STATE::EXPLODE) {
jjDrawSprite(obj.xPos, obj.yPos, ANIM::MONKEY, 1, obj.curFrame, obj.direction, SPRITE::SINGLEHUE, obj.eventID == OBJECT::FIREBALLBULLETPU? 15:24);
if (obj.var[1] < 27) {
if (obj.var[1] == 1) jjSample(obj.xPos, obj.yPos, SOUND::HATTER_SPLOUT, 0, 20000);
obj.var[1] = obj.var[1] + 1;
}
if (obj.var[1] == 27) {
obj.var[1] = 0;
obj.delete();
}
}
}
void Lightningrod(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BULLET, false);
jjDrawSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[27], obj.var[0] == 1? obj.var[4] : 0, obj.var[0] == 1? jjGameTicks / 10 % 6 : 0, obj.direction, SPRITE::NORMAL);
if (obj.counter == 2) {
obj.age = 0;
obj.var[1] = 0;
}
if (obj.counter == 127) obj.counter = 2;
if (!jjMaskedHLine(int(obj.xPos - 16), 24, int(obj.yPos + 8))) {
obj.yPos += 6;
obj.var[0] = 0;
obj.lightType = LIGHT::POINT;
} else {
obj.var[0] = 1;
}
if (obj.var[0] == 1) {
obj.age++;
if (obj.var[1] == 0) {
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_LANDCAN1, 0, 30000);
obj.var[1] = 1;
}
obj.lightType = LIGHT::BRIGHT;
obj.light = 10;
if (obj.age % 20 == 0) {
for (int i = -4; i <= 4; i += 4) {
int id = jjAddObject(OBJECT::LIGHTNINGSHIELDBULLET, obj.xPos, obj.yPos - 12, obj.creatorID, CREATOR::OBJECT, Electricity);
if (id != 0) {
jjOBJ@ zap = jjObjects[id];
zap.lightType = LIGHT::NONE;
zap.counterEnd = 6;
zap.direction = obj.direction;
zap.lightType = LIGHT::NONE;
zap.playerHandling = HANDLING::ENEMYBULLET;
zap.var[3] = 1;
zap.var[6] = 8;
zap.xSpeed = i;
zap.xAcc = 0;
zap.animSpeed = 1;
if (i == 0) zap.ySpeed = -4;
}
}
}
}
if (obj.age == 420) {
obj.var[0] = obj.var[1] = 0;
obj.particlePixelExplosion(0);
obj.delete();
}
}
void Electricity(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BULLET, false);
}
void onFunction0(jjPLAYER@ player) {
player.activateBoss();
jjTriggers[1] = true;
player.invincibility = 0;
jjMusicLoad("fireeye.ogg");
player.limitXScroll(uint(136), uint(26));
}
class CloneMachine: jjBEHAVIORINTERFACE {
uint recharge, maxHP;
int currentHP;
CloneMachine(jjOBJ@ preset) {
preset.behavior = this;
preset.playerHandling = HANDLING::SPECIAL;
preset.bulletHandling = HANDLING::DETECTBULLET;
preset.scriptedCollisions = true;
preset.isTarget = false;
preset.isFreezable = false;
preset.isBlastable = false;
preset.triggersTNT = false;
preset.deactivates = false;
preset.determineCurAnim(ANIM::CUSTOM[28], 0);
//preset.determineCurFrame();
preset.curFrame = 2;
preset.direction = 1;
preset.special = 0;
preset.counter = 0;
preset.frameID = 2;
preset.energy = 100;
recharge = (jjDifficulty <= 0) ? 320 : (jjDifficulty == 1) ? 280 : 240;
maxHP = (jjDifficulty <= 0) ? 200 : (jjDifficulty == 1) ? 250 : 325;
currentHP = maxHP;
}
void onBehave(jjOBJ @ obj) {
obj.energy = 100 * currentHP / maxHP;
int playerID = obj.findNearestPlayer(8000000);
if (jjPlayers[playerID].bossActivated == false && bossDefeated == false) return;
if (uint(obj.special) < recharge && obj.state != STATE::EXTRA) {
obj.special++;
}
else if (uint(obj.special) >= recharge && obj.state != STATE::KILL && obj.state != STATE::EXTRA) obj.special = 0;
if (obj.state == STATE::START) {
jjPlayers[playerID].boss = obj.objectID;
obj.putOnGround();
}
if (obj.special == 140 && loriCounter < 5 && obj.state != STATE::EXTRA) {
if (obj.counter == 0) { // preventing double Lori spawn
switch (jjRandom()%4) {
case 0: jjParameterSet(151, 11, 0, 3, 0); break;
case 1: jjParameterSet(151, 11, 0, 3, 1); break;
case 2: jjParameterSet(151, 11, 0, 3, 2); break;
case 3: jjParameterSet(151, 11, 0, 3, 5); break;
}
jjObjects[jjAddObject(OBJECT::MORPH, obj.xPos - 150, obj.yPos - 20)];
jjSample(jjPlayers[playerID].xPos, jjPlayers[playerID].yPos, SOUND::COMMON_TELPORT2);
loriCounter++;
obj.counter = 1;
}
}
else obj.counter = 0;
if (playerID > -1) {
if (obj.age > 0) obj.age--;
jjPLAYER@ play;
float dx = jjPlayers[playerID].xPos - obj.xPos + 80, dy = jjLocalPlayers[playerID].yPos + 50 - obj.yPos;
if (dx * dx + dy * dy < 140 * 140) {
obj.age = 35;
jjPlayers[playerID].xSpeed = -8 * obj.direction;
//jjPlayers[playerID].ySpeed = -8 * obj.direction;
//jjPlayers[playerID].hurt(0, false);
}
}
if (obj.justHit == 0 && obj.state != STATE::EXTRA) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NORMAL, 0, 5);
} else if (obj.state != STATE::EXTRA)
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::SINGLECOLOR, 28, 5);
bossStarted = true;
if (obj.state == STATE::KILL) {
jjPlayers[playerID].activateBoss(false);
jjSample(jjPlayers[playerID].xPos, jjPlayers[playerID].yPos, SOUND::INTRO_BOEM2);
jjNxt(false, false);
bossDefeated = true;
obj.special = 254;
obj.state = STATE::EXTRA;
}
if (obj.state == STATE::EXTRA) {
if (obj.special > 0)
obj.special--;
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::BLEND_DISSOLVE, obj.special);
}
if (obj.justHit == 1) {
switch (jjRandom()%5) {
case 0: jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_METAL1); break;
case 1: jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_METAL2); break;
case 2: jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_METAL3); break;
case 3: jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_METAL4); break;
case 4: jjSample(obj.xPos, obj.yPos, SOUND::ROBOT_METAL5); break;
}
}
if (loriCounter < 5 && obj.state != STATE::EXTRA) {
if (obj.special == 120 || obj.special == 200) obj.frameID = 1;
if (obj.special == 220) obj.frameID = 2;
if (obj.special == 140) obj.frameID = 0;
}
else obj.frameID = 2;
obj.curFrame = jjAnimations[jjAnimSets[ANIM::CUSTOM[28]]].firstFrame + (obj.frameID % jjAnimations[jjAnimSets[ANIM::CUSTOM[28]]].frameCount);
}
bool onObjectHit(jjOBJ @ obj, jjOBJ @ bullet, jjPLAYER @ player, int force) {
if (bullet !is null) {
bullet.state = STATE::EXPLODE;
obj.justHit = 5; //flash white for 5 ticks--jjOBJ::justHit is automatically deincremented by the JJ2 engine, so individual behavior functions don't need to worry about doing that.
currentHP -= bullet.animSpeed;
if (currentHP <= 0) { //killed
currentHP = 0;
obj.state = STATE::KILL;
}
}
return true;
}
}
bool onCheat(string &in cheat) {
jjPLAYER@ Player = jjLocalPlayers[0];
if (cheat == "jjgems")
Player.gems[GEM::RED] = Player.gems[GEM::RED] + 100;
else if (cheat == "jjmorph" || cheat == "jjcolor")
return true; // forcing the player to play as canon Lori
else if ((cheat == "jjk" || cheat == "jjkill") && Player.health <= 0) { ; }
else if (cheat == "jjlori")
jjSample(Player.xPos, Player.yPos, SOUND::LORISOUNDS_TOUCH);
else
return false;
jjAlert(cheat, false, STRING::MEDIUM);
return true;
}
Jazz2Online © 1999-INFINITY (Site Credits). We have a Privacy Policy. Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats.
Eat your lima beans, Johnny.