Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Holiday Hare '17 | ShadowGPW | Single player | 8.8 |
#include "MLLE-Include-1.6.asc" ///@MLLE-Generated
const bool MLLESetupSuccessful = MLLE::Setup();
#pragma require "HH17_Guardian.j2l"
#pragma require "Icicle.j2a"
#pragma require "HH17_Dragon.j2a"
#pragma require "SEXmas.j2a"
#pragma require "HH17_Roar.wav"
bool dragonActivated = false;
enum dragonStates {Intro, Idle, Roar, Homing_Fire, Flamethrower, Flame_Burst, Firebombs, Spawn_FireOrb, Shockwave};
uint currState = Intro;
int randcar = 20;
int frameRate = 7;
int shockSpeed = 3;
int healthFactor = 7;
int elapsed = 0;
bool charging = false;
bool defeated = false;
void singleColorLayer(jjLAYER@ layer, int color) {
array<int> tileIDs, uniqueTileIDs;
for (int i = 0; i < layer.height; i++) {
for (int j = 0; j < layer.width; j++) {
int tileID = layer.tileGet(j, i);
if (tileID != 0)
tileIDs.insertLast(tileID);
}
}
int prev = 0;
tileIDs.sortAsc();
for (uint i = 0; i < tileIDs.length(); i++) {
if (tileIDs[i] != prev)
uniqueTileIDs.insertLast(prev = tileIDs[i]);
}
uint firstNewTile = jjTileCount;
jjTilesFromTileset(jjTilesetFileName, 1, uniqueTileIDs.length());
for (uint i = 0; i < uniqueTileIDs.length(); i++) {
jjPIXELMAP tile(uniqueTileIDs[i]);
for (int j = 0; j < 32; j++) {
for (int k = 0; k < 32; k++) {
uint8 pixel = tile[k, j];
if (pixel != 0) {
tile[k, j] = color;
}
}
}
tile.save(firstNewTile + i);
}
layer.generateSettableTileArea();
for (int i = 0; i < layer.height; i++) {
for (int j = 0; j < layer.widthReal; j++) {
int tileID = layer.tileGet(j, i);
if (tileID != 0)
layer.tileSet(j, i, firstNewTile + uniqueTileIDs.find(tileID));
}
}
}
void onLevelLoad() {
jjUseLayer8Speeds = true;
jjTexturedBGFadePositionY = 0.52;
singleColorLayer(jjLayers[6], 176);
singleColorLayer(jjLayers[7], 204);
jjAnimSets[ANIM::CUSTOM[0]].load(0, "HH17_Dragon.j2a");
jjOBJ@ preset = jjObjectPresets[OBJECT::LIZARD];
preset.determineCurAnim(ANIM::CUSTOM[0], 0);
preset.behavior = DragonBoss();
preset.energy = 100;
preset.points = 50000;
preset.scriptedCollisions = true;
preset.playerHandling = HANDLING::SPECIAL;
preset.bulletHandling = HANDLING::DETECTBULLET;
preset.isBlastable = false;
preset.isTarget = false;
preset.special = 0;
preset.animSpeed = 2;
switch (jjDifficulty) {
case 0: preset.age = 500; healthFactor = 5; break;
case 1: preset.age = 700; healthFactor = 7; break;
case 2: preset.age = 900; healthFactor = 9; break;
default: preset.age = 900; healthFactor = 9; break;
}
jjAnimSets[ANIM::CUSTOM[2]].load(0, "HH17_Icicle.j2a");
jjSampleLoad(SOUND::P2_FOEW1, "HH17_Glass2.wav");
jjSampleLoad(SOUND::P2_FOEW4, "HH17_Glass3.wav");
jjSampleLoad(SOUND::P2_FOEW5, "HH17_Glass4.wav");
jjSampleLoad(SOUND::INTRO_MONSTER, "HH17_Roar.wav");
jjAnimSets[ANIM::CUSTOM[1]].load(2, "SExmas.j2a");
jjObjectPresets[OBJECT::BOMBCRATE].behavior = GiftBox();
jjObjectPresets[OBJECT::BOMBCRATE].determineCurAnim(ANIM::CUSTOM[1], 0);
jjObjectPresets[OBJECT::ICEBULLET].var[3] = jjObjectPresets[OBJECT::ICEBULLETPU].var[3] = 3;
}
void onLevelReload() {
onLevelLoad();
currState = Intro;
}
bool inView(const jjOBJ@ obj) {
for (int i = 0; i < jjLocalPlayerCount; i++) {
const jjPLAYER@ player = jjLocalPlayers[i];
if (obj.xPos > player.cameraX - 64 && obj.yPos > player.cameraY - 64 && obj.xPos < player.cameraX + jjSubscreenWidth + 64 && obj.yPos < player.cameraY + jjSubscreenHeight + 64)
return true;
}
return false;
}
void onLevelBegin() {
jjPIXELMAP blackTile(243);
for (uint x = 0; x < blackTile.width; ++x) {
for (uint y = 0; y < blackTile.height; ++y) {
blackTile[x,y] = 180;
}
}
blackTile.save(243, true);
}
class GiftBox : jjBEHAVIORINTERFACE {
void destroy(jjOBJ@ obj) {
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_WOOD1);
{
int id = jjAddObject(OBJECT::EXPLOSION, obj.xPos, obj.yPos);
if (id != 0) {
jjOBJ@ other = jjObjects[id];
other.determineCurAnim(ANIM::PICKUPS, 4);
}
}
for (int i = jjRandom() & 7 | 8; i-- != 0;) {
int id = jjAddObject(OBJECT::SHARD, obj.xPos, obj.yPos);
if (id != 0) {
jjOBJ@ other = jjObjects[id];
other.determineCurAnim(ANIM::PICKUPS, 93 + (jjRandom() & 1));
}
}
obj.yPos -= 8.f;
for (int i = obj.var[1]; i-- != 0;) {
int id = jjAddObject(obj.var[0], obj.xPos, obj.yPos);
if (id != 0) {
jjOBJ@ other = jjObjects[id];
if (other.playerHandling == HANDLING::PICKUP) {
int angle = (jjRandom() & 255) + 128;
other.xSpeed = jjCos(angle) * 5.f;
other.ySpeed = jjSin(angle) * -3.f;
} else if (other.playerHandling == HANDLING::SPECIAL) {
other.deactivates = false;
}
}
}
obj.clearPlatform();
obj.delete();
}
void onBehave(jjOBJ@ obj) override {
switch (obj.state) {
case STATE::START:
{
uint16 x = int(obj.xOrg) >>> 5;
uint16 y = int(obj.yOrg) >>> 5;
obj.var[0] = jjParameterGet(x, y, 0, 8);
obj.var[1] = jjParameterGet(x, y, 8, 4);
obj.curAnim += jjParameterGet(x, y, 12, 2);
obj.determineCurFrame();
obj.bulletHandling = HANDLING::DESTROYBULLET;
obj.scriptedCollisions = true;
}
break;
case STATE::FALL:
obj.var[2] = 1;
break;
case STATE::FREEZE:
case STATE::SLEEP:
if (obj.var[2] != 0) {
destroy(obj);
return;
}
}
obj.behave(BEHAVIOR::MONITOR);
}
bool onObjectHit(jjOBJ@, jjOBJ@, jjPLAYER@, int) {
return true;
}
bool onIsSolid(jjOBJ@) {
return true;
}
}
class DragonBoss : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.determineCurFrame();
if (obj.freeze == 0 && obj.var[5] == 0) {
if (jjGameTicks % frameRate == 0) obj.frameID++;
obj.special++;
}
frameRate = obj.energy > 50? 7 : obj.energy < 25? 4 : 5;
shockSpeed = obj.energy < 50? 4:3;
if (obj.energy < 25 && obj.var[5] == 0) {
dragonShout(obj, 36);
if (obj.special % 250 == 0) jjSamplePriority(SOUND::INTRO_MONSTER);
}
if (obj.energy < 25 && obj.var[9] == 0) {
jjLocalPlayers[0].showText("@@@@@@@Uh-oh! You've made the dragon very angry indeed!", STRING::MEDIUM);
obj.var[9] = 1;
}
if (obj.frameID > 20) obj.frameID = currState == Idle? 15:0;
if (obj.state != STATE::KILL) {
if (obj.var[5] == 0) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, obj.justHit > 0? SPRITE::SINGLECOLOR : obj.freeze > 0? SPRITE::FROZEN : SPRITE::SINGLEHUE, obj.justHit > 0? 15:71);
if (obj.justHit == 0 && obj.freeze == 0 && jjColorDepth == 16) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NEONGLOW, 3);
if (charging && obj.special % 5 == 0) jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::TRANSLUCENTCOLOR, 15);
if (obj.energy < 75) jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NEONGLOW, 0);
if (obj.energy < 50) jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NEONGLOW, 0);
if (obj.energy < 25) jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NEONGLOW, 0);
}
} else if (obj.var[5] % 10 > 3) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, obj.justHit > 0? SPRITE::SINGLECOLOR : obj.freeze > 0? SPRITE::FROZEN : SPRITE::SINGLEHUE, obj.justHit > 0? 15:71);
if (obj.justHit == 0 && obj.freeze == 0 && jjColorDepth == 16) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NEONGLOW, 0);
if (obj.energy < 75) jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NEONGLOW, 0);
if (obj.energy < 50) jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NEONGLOW, 0);
if (obj.energy < 25) jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NEONGLOW, 0);
}
}
}
obj.direction = 1;
obj.yPos = obj.yOrg + 8;
for (int i = 0; i < jjLocalPlayerCount; i++) {
if (jjLocalPlayers[i].xPos > obj.xPos) jjLocalPlayers[i].xPos = obj.xPos;
}
if (obj.var[1] == 0) {
jjOBJ@ target = jjObjects[jjAddObject(OBJECT::FLICKERLIGHT, obj.xPos - 32, obj.yPos - 140)];
target.isTarget = true;
target.light = 0;
target.lightType = LIGHT::NONE;
obj.var[1] = 1;
}
if (obj.state == STATE::FREEZE) {
obj.var[10] = obj.var[10] - 1;
if (obj.var[10] == 0) {
obj.unfreeze(1);
obj.state = obj.oldState;
}
} else {
obj.var[10] = 105;
}
switch (jjDifficulty) {
case 0: randcar = obj.energy < 25? 15:10; break;
case 1: randcar = obj.energy < 25? 25:15; break;
case 2: randcar = obj.energy < 25? 30:20; break;
default: randcar = obj.energy < 25? 30:20; break;
}
switch (currState) {
case Intro:
for (int i = 0; i < jjLocalPlayerCount; i++) {
if (inView(obj)) {
obj.var[11] = 1;
if (obj.frameID == 7 && obj.special % 7 == 0) {
jjSamplePriority(SOUND::INTRO_MONSTER);
}
}
if (obj.var[11] == 0) {
obj.frameID = 0;
obj.special = 0;
}
if (obj.special >= 185 && obj.frameID >= 15 && obj.frameID <= 20) {
currState = Flamethrower;
obj.special = 0;
}
}
break;
case Idle:
if (obj.frameID < 15) obj.frameID = 15;
if (obj.frameID == 20) obj.frameID = 15;
if (obj.special >= 105) {
randomAttack(obj);
}
break;
case Roar:
if (obj.frameID == 8 && obj.special % 7 == 1) {
jjSamplePriority(SOUND::INTRO_MONSTER);
jjSample(jjLocalPlayers[0].xPos, jjLocalPlayers[0].yPos, CollapsingIceSounds[jjRandom()%3]);
obj.var[4] = 1;
}
if (obj.frameID >= 9 && obj.var[4] == 1) {
dragonShout(obj, obj.energy < 50? 7:9);
int playerID = obj.findNearestPlayer(100000);
if (playerID >= -1) {
jjPlayers[playerID].xSpeed = jjPlayers[playerID].xSpeed - 1;
}
}
if ((obj.special >= 70 && obj.frameID == 0) || obj.energy < 25) {
randomAttack(obj);
obj.var[4] = 0;
jjLocalPlayers[0].cameraUnfreeze();
}
break;
case Homing_Fire:
if (obj.frameID >= 7 && obj.frameID <= 10) {
if (obj.counter < 7) {
if (obj.counter % 7 == 0 && obj.freeze == 0 && obj.var[5] == 0) {
jjOBJ@ bullet = jjObjects[obj.fireBullet(OBJECT::BULLET)];
bullet.determineCurAnim(ANIM::BILSBOSS, 3);
bullet.animSpeed = 1;
bullet.behavior = HomingBullet();
bullet.playerHandling = HANDLING::ENEMYBULLET;
bullet.triggersTNT = true;
bullet.isBlastable = true;
}
if (obj.counter == 1) {
int playerID = obj.findNearestPlayer(40000);
if (playerID >= -1) {
jjSamplePriority(SOUND::DEVILDEVAN_DRAGONFIRE);
jjSamplePriority(SOUND::BILSBOSS_FIRE);
}
}
}
obj.counter++;
}
else obj.counter = 0;
if (obj.special >= 140 && obj.frameID >= 15 && obj.frameID <= 20) {
randomAttack(obj);
}
break;
case Flamethrower:
if (obj.frameID == 5 && obj.special % 7 == 0 && obj.var[5] == 0) jjSamplePriority(SOUND::BILSBOSS_FIRESTART);
if (obj.frameID >= 7 && obj.frameID <= 10) {
obj.var[4] = 1;
int playerID = obj.findNearestPlayer(1000000);
int sine = obj.energy > 50? 1: obj.energy < 25? 3:2;
if (obj.counter % 1 == 0 && obj.freeze == 0 && obj.var[5] == 0) {
jjOBJ@ bullet = jjObjects[obj.fireBullet(OBJECT::TOASTERBULLETPU)];
bullet.behavior = Firebreather();
bullet.lightType = LIGHT::POINT;
bullet.playerHandling = HANDLING::ENEMYBULLET;
bullet.animSpeed = 1;
bullet.xSpeed = -16;
float ys = jjRandom()%sine + (jjCos(obj.counter*32)) + jjSin(obj.counter*2)*2;
bullet.ySpeed = ys;
bullet.counterEnd = 165;
}
if (obj.counter == 1) {
if (playerID >= -1) {
jjSamplePriority(SOUND::BILSBOSS_FIRE);
}
}
if (obj.counter % 35 == 0 && obj.counter > 1 && obj.freeze == 0 && obj.var[5] == 0) jjSamplePriority(SOUND::COMMON_FLAMER);
obj.counter++;
}
else obj.counter = 0;
if (obj.var[4] == 1 && obj.special < 490 && obj.frameID > 9) obj.frameID = 7;
if (obj.special >= 490 && obj.frameID >= 15 && obj.frameID <= 20) {
randomAttack(obj);
obj.var[4] = 0;
}
break;
case Flame_Burst:
if (obj.frameID >= 7 && obj.frameID <= 10 && obj.var[5] == 0) {
obj.var[4] = 1;
int playerID = obj.findNearestPlayer(1000000);
int fireRate = obj.energy < 50? 6:10;
if (obj.counter % fireRate == 0 && obj.freeze == 0) {
jjOBJ@ bullet = jjObjects[obj.fireBullet(OBJECT::FIRESHIELDBULLET)];
bullet.behavior = BEHAVIOR::BULLET;
bullet.lightType = LIGHT::POINT;
bullet.playerHandling = HANDLING::ENEMYBULLET;
bullet.animSpeed = 1;
bullet.xSpeed = -6;
bullet.xAcc = 0;
bullet.yAcc = 0;
float ys = jjRandom()%4 + (jjCos(obj.counter*32));
bullet.ySpeed = ys;
bullet.counterEnd = 200;
}
if (obj.counter == 1) {
if (playerID >= -1) {
jjSamplePriority(SOUND::BILSBOSS_FIRE);
}
}
if (obj.counter % fireRate == 0 && obj.counter > 1 && obj.freeze == 0) jjSamplePriority(jjRandom()%2 > 0? SOUND::AMMO_FIREGUN1A : SOUND::AMMO_FIREGUN2A);
obj.counter++;
}
else obj.counter = 0;
if (obj.var[4] == 1 && obj.special < 350 && obj.frameID > 9) obj.frameID = 7;
if (obj.special >= 350 && obj.frameID >= 15 && obj.frameID <= 20) {
randomAttack(obj);
obj.var[4] = 0;
}
break;
case Firebombs:
if (obj.frameID >= 7 && obj.frameID <= 10 && obj.var[5] == 0) {
obj.var[4] = 1;
int playerID = obj.findNearestPlayer(1000000);
int fireRate = obj.energy < 50? 9:14;
if (obj.counter % fireRate == 0 && obj.freeze == 0) {
jjOBJ@ bullet = jjObjects[obj.fireBullet(OBJECT::FIRESHIELDBULLET)];
jjSamplePriority(SOUND::BILSBOSS_FIRE);
bullet.behavior = Firebomb();
bullet.special = bullet.determineCurAnim(ANIM::BUBBA, 4);
bullet.lightType = LIGHT::POINT;
bullet.playerHandling = HANDLING::ENEMYBULLET;
bullet.animSpeed = 1;
bullet.xSpeed = -(4 + jjRandom()%3);
bullet.ySpeed = -(6 + jjRandom()%3);
bullet.xAcc = 0;
bullet.yAcc = 0;
bullet.counterEnd = 200;
bullet.killAnim = jjObjectPresets[OBJECT::SEEKERBULLET].killAnim;
}
if (obj.counter == 1) {
if (playerID >= -1) {
jjSamplePriority(SOUND::BILSBOSS_FIRESTART);
}
}
obj.counter++;
}
else obj.counter = 0;
if (obj.var[4] == 1 && obj.special < 350 && obj.frameID > 9) obj.frameID = 7;
if (obj.special >= 350 && obj.frameID >= 15 && obj.frameID <= 20) {
randomAttack(obj);
obj.var[4] = 0;
}
break;
case Spawn_FireOrb:
if (obj.frameID >= 7 && obj.frameID <= 10 && obj.var[5] == 0) {
if (obj.counter < 7) {
if (obj.counter % 7 == 0 && obj.freeze == 0) {
jjOBJ@ orb = jjObjects[obj.fireBullet(OBJECT::SPARK)];
orb.determineCurAnim(ANIM::AMMO, 77);
orb.behavior = FireOrb();
orb.playerHandling = HANDLING::SPECIAL;
orb.bulletHandling = HANDLING::DETECTBULLET;
orb.energy = 4;
orb.triggersTNT = true;
orb.isBlastable = true;
orb.scriptedCollisions = true;
}
if (obj.counter == 1) {
int playerID = obj.findNearestPlayer(40000);
if (playerID >= -1) {
jjSamplePriority(SOUND::DEVILDEVAN_DRAGONFIRE);
jjSamplePriority(SOUND::BILSBOSS_FIRE);
}
}
}
obj.counter++;
}
else obj.counter = 0;
if (obj.special >= 140 && obj.frameID >= 15 && obj.frameID <= 20) {
randomAttack(obj);
}
break;
case Shockwave:
if (obj.frameID >= 7 && obj.frameID <= 10 && obj.var[5] == 0) {
if (obj.counter == 1 && obj.freeze == 0) {
jjOBJ@ blast = jjObjects[obj.fireBullet(OBJECT::BULLET)];
blast.behavior = DragonShockwave();
blast.lightType = LIGHT::RING;
blast.light = 100;
}
obj.counter++;
}
else obj.counter = 0;
if (obj.special >= 140 && obj.frameID >= 15 && obj.frameID <= 20) {
randomAttack(obj);
}
break;
}
if (obj.freeze == 0 && dragonActivated) obj.special++;
obj.energy = int(obj.age / healthFactor);
if (obj.animSpeed <= 0) {
obj.age -= 1;
obj.animSpeed = 2;
}
if (obj.age < 1) {
obj.var[5] = obj.var[5] + 1;
if (obj.var[5] < 350) {
jjMusicStop();
for (int i = 1; i < jjObjectCount; i++) {
if (jjObjects[i].eventID == OBJECT::SPARK) jjObjects[i].state = STATE::KILL;
}
if (obj.var[5] == 10) {
jjSample(jjLocalPlayers[0].xPos, jjLocalPlayers[0].yPos, SOUND::INTRO_MONSTER, 63, 45000);
jjLocalPlayers[0].cameraUnfreeze(true);
}
if (obj.var[5] % 7 == 0 && obj.var[5] > 35) {
jjOBJ@ boem = jjObjects[jjAddObject(OBJECT::EXPLOSION, int(obj.xPos - 130) + jjRandom()%260, int(obj.yPos) - jjRandom()%160)];
boem.determineCurAnim(ANIM::AMMO, 5);
jjSample(boem.xPos, boem.yPos, SOUND::COMMON_EXPL_TNT, 48, 0);
}
} else {
for (int i = 0; i < 30; i++) {
obj.particlePixelExplosion(1);
obj.particlePixelExplosion(2);
}
for (int j = 0; j < jjLocalPlayerCount; j++) {
givePlayerPointsForObject(jjLocalPlayers[j], obj);
jjLocalPlayers[j].bossActivated = false;
}
jjLocalPlayers[0].showText("@@@@@@@@#||||~DRAGON SLAIN", STRING::LARGE);
defeated = true;
obj.delete();
}
} else obj.var[5] = 0;
if (jjLocalPlayers[0].bossActivated) {
jjLocalPlayers[0].boss = obj.objectID;
}
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bull, jjPLAYER@ play, int force) {
if (bull !is null) {
if (bull.playerHandling == HANDLING::PLAYERBULLET && obj.var[5] == 0) {
if (bull.var[3] != 6) obj.age -= (bull.var[3] == 9? bull.animSpeed + 1 : bull.animSpeed) * ((bull.yPos < obj.yPos - 92) && (bull.xPos < obj.xPos + 8)? 2:1);
else obj.animSpeed -= bull.animSpeed;
obj.justHit = (bull.yPos < obj.yPos - 92) && (bull.xPos < obj.xPos + 8)? 7:5;
if (obj.freeze > 0) {
obj.unfreeze(1);
obj.energy -= bull.animSpeed;
}
}
if ((bull.var[6] & 16) == 0 || obj.var[5] == 0) {
bull.state = STATE::EXPLODE;
}
} else if (play !is null) {
if (obj.var[5] == 0) play.hurt();
play.xSpeed = -6 * obj.direction;
}
return true;
}
}
const array<SOUND::Sample> CollapsingIceSounds = {
SOUND::P2_FOEW1,
SOUND::P2_FOEW4,
SOUND::P2_FOEW5
};
class Firebreather : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::TOASTERBULLET, false);
if (obj.state != STATE::EXPLODE) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, 8);
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::ALPHAMAP, 25);
obj.xPos -= 3;
}
}
}
class HomingBullet : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BILSYBULLET);
if (obj.counter > 70) obj.counter = 1;
for (int i = 1; i < jjObjectCount; i++) {
if (jjObjects[i].playerHandling == HANDLING::PLAYERBULLET && jjObjects[i].doesCollide(obj, true)) {
jjObjects[i].state = STATE::EXPLODE;
}
}
}
}
class Firebomb : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BULLET, obj.state == STATE::EXPLODE? true:false);
obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
if (obj.state != STATE::EXPLODE) {
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.var[0], 1, 1, SPRITE::NORMAL);
if (obj.ySpeed < 8) obj.ySpeed += 0.15;
}
}
}
class FireOrb : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::SPARK, false);
obj.special++;
if (obj.special < 35) obj.xPos -= 4;
else {
obj.xPos += jjSin(obj.special*8);
obj.yPos += jjCos(obj.special*8);
}
if (obj.energy < 1) obj.state = STATE::KILL;
int carDropRate = jjDifficulty == 0? 1 : jjDifficulty == 1? 2 : 4;
if (obj.state != STATE::KILL) {
jjDrawSprite(obj.xPos, obj.yPos, ANIM::AMMO, 77, 5, obj.direction, obj.justHit > 0? SPRITE::SINGLECOLOR : SPRITE::NORMAL, 15);
} else {
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BURN, 0, 0);
obj.particlePixelExplosion(1);
if (jjRandom()%carDropRate == 0) {
jjOBJ@ carrot = jjObjects[jjAddObject(OBJECT::CARROT, int(obj.xPos), int(obj.yPos), obj.objectID, CREATOR::OBJECT)];
carrot.state = STATE::FLOATFALL;
}
obj.delete();
}
int playerID = obj.findNearestPlayer(60000);
if (playerID > -1) {
if (obj.special % 60 == 0 && !jjMaskedPixel(int(obj.xPos), int(obj.yPos), 4)) {
jjOBJ@ bullet = jjObjects[jjAddObject(OBJECT::FIRESHIELDBULLET, obj.xPos, obj.yPos)];
bullet.xSpeed = jjPlayers[playerID].xPos > obj.xPos? 4:-4;
bullet.state = STATE::FLY;
bullet.playerHandling = HANDLING::ENEMYBULLET;
bullet.animSpeed = 1;
bullet.counterEnd = 105;
bullet.xAcc = 0;
}
}
for (int i = 1; i < jjObjectCount; i++) {
if (jjObjects[i].var[3] == 3 && jjObjects[i].doesCollide(obj, true)) obj.state = STATE::KILL;
}
jjPARTICLE@ cinders = jjAddParticle(PARTICLE::SMOKE);
cinders.xPos = int(obj.xPos - 8) + jjRandom()%16;
cinders.yPos = obj.yPos;
cinders.ySpeed = -0.5;
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bull, jjPLAYER@ play, int force) {
if (bull !is null) {
if (bull.playerHandling == HANDLING::PLAYERBULLET) {
if (bull.var[3] != 6) {
obj.energy -= bull.animSpeed;
obj.justHit = 5;
}
}
if ((bull.var[6] & 16) == 0) {
bull.state = STATE::EXPLODE;
}
} else if (play !is null) {
play.hurt();
}
return true;
}
}
class Icicle : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BULLET, false);
obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
if (obj.state == STATE::EXPLODE) {
obj.unfreeze(1);
obj.delete();
} else {
obj.xAcc = 0;
obj.yAcc = 0;
jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[2], 0, 0, obj.var[0], 1, 1, SPRITE::SINGLEHUE, 32);
}
}
}
class DragonShockwave : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::STEADYLIGHT, false);
obj.xPos = obj.xOrg + 24;
obj.lightType = obj.var[0] == 1? LIGHT::RING2 : LIGHT::RING;
obj.var[1] = obj.light * 4;
obj.counter++;
if (obj.counter == 1) {
obj.light = 100;
jjSamplePriority(SOUND::ORANGE_SWEEP0L);
}
if (obj.counter > 150) obj.delete();
if (obj.var[0] == 0) {
if (obj.light > 0) {
obj.light--;
charging = true;
} else {
obj.var[0] = 1;
for (int i = 0; i < 5; i++) {
jjSamplePriority(SOUND::ORANGE_BOEMR);
}
charging = false;
}
} else {
obj.light += 3;
}
for (int i = 0; i < jjLocalPlayerCount; i++) {
jjPLAYER@ play = jjLocalPlayers[i];
float dx = play.xPos - obj.xPos, dy = play.yPos - obj.yPos;
if (dx * dx + dy * dy < obj.var[1] * obj.var[1]) {
if (obj.var[8] & 1 << i == 0 && obj.var[0] == 1) {
play.hurt(2, play.blink == 0 && play.buttstomp < 41? true:false);
obj.var[8] = obj.var[8] | 1 << i;
}
}
}
for (int j = 1; j < jjObjectCount; j++) {
jjOBJ@ bull = jjObjects[j];
float dx = bull.xPos - obj.xPos, dy = bull.yPos - obj.yPos;
if (dx * dx + dy * dy < obj.var[1] * obj.var[1]) {
if (bull.playerHandling == HANDLING::PLAYERBULLET && bull.var[9] == 0 && obj.var[0] == 1) {
bull.ricochet();
}
}
}
}
}
const array<dragonStates> closeRangeAttacks = {Idle, Roar, Roar, Homing_Fire, Homing_Fire, Spawn_FireOrb, Shockwave};
const array<dragonStates> longRangeAttacks = {Idle, Idle, Roar, Homing_Fire, Flame_Burst, Flame_Burst, Flamethrower, Firebombs};
array<dragonStates> closeRangeQueue;
array<dragonStates> longRangeQueue;
void shuffle(array<dragonStates>& input) {
for (int i = input.length(); i != 0;) {
int index = jjRandom() % i;
i--;
dragonStates temp = input[index];
input[index] = input[i];
input[i] = temp;
}
}
dragonStates pop(array<dragonStates>& input) {
dragonStates result = input[input.length() - 1];
input.removeLast();
return result;
}
dragonStates getNextAttack(array<dragonStates>& queue, const array<dragonStates>& reserve) {
if (queue.isEmpty()) {
queue = reserve;
shuffle(queue);
}
return pop(queue);
}
void randomAttack(jjOBJ@ obj) {
int playerID = obj.findNearestPlayer(100000);
if (playerID > -1)
currState = getNextAttack(closeRangeQueue, closeRangeAttacks);
else
currState = getNextAttack(longRangeQueue, longRangeAttacks);
obj.special = 0;
obj.counter = 0;
}
void dragonShout(jjOBJ@ obj, int rate) {
uint random = jjRandom();
int magnitude = (2 << (random & 3)) - 1;
int halfMagnitude = magnitude >> 1;
if (jjGameTicks & 1 == 0)
jjLocalPlayers[0].cameraFreeze(jjLocalPlayers[0].cameraX + (random >> 8 & magnitude) - halfMagnitude, jjLocalPlayers[0].cameraY + (random >> 2 & magnitude) - halfMagnitude, false, true);
else
jjLocalPlayers[0].cameraUnfreeze();
int fireRate = rate;
if (obj.special % fireRate == 0) {
if (jjRandom()%randcar < (randcar - 1)) {
Icicle temp;
jjOBJ@ icicle = jjObjects[jjAddObject(OBJECT::BLASTERBULLET, (int(obj.xPos - 890) + jjRandom()%830), int(obj.yPos - 580), obj.objectID, CREATOR::OBJECT, jjVOIDFUNCOBJ(temp.onBehave))];
icicle.xSpeed = 0;
icicle.ySpeed = 6;
icicle.direction = 1;
icicle.counterEnd = 200;
icicle.state = STATE::FLY;
icicle.playerHandling = HANDLING::ENEMYBULLET;
icicle.lightType = LIGHT::NONE;
} else {
jjOBJ@ carrot = jjObjects[jjAddObject(OBJECT::CARROT, (int(obj.xPos - 890) + jjRandom()%830), int(obj.yPos - 580), obj.objectID, CREATOR::OBJECT)];
carrot.state = STATE::FLOATFALL;
}
}
}
bool givePlayerPointsForObject(jjPLAYER@ player, jjOBJ@ obj) { //This will probably be made a jjOBJ method as part of the real JJ2+ API eventually, because it shows up all the time in the native code, but that hasn't happened yet, so here you go. Increases the player's jjPLAYER::score to match the object's jjOBJ::points, and creates a string particle with that number which flies up to the top left corner of the screen.
if (player is null)
return false;
if (obj.points != 0 && (jjGameMode == GAME::SP || jjGameMode == GAME::COOP)) {
player.score += obj.points;
jjPARTICLE@ particle = jjAddParticle(PARTICLE::STRING);
if (particle !is null) {
particle.xPos = obj.xPos;
particle.yPos = obj.yPos;
particle.xSpeed = (-32768 - int(jjRandom() & 0x3FFF)) / 65536.f;
particle.ySpeed = (-65536 - int(jjRandom() & 0x7FFF)) / 65536.f;
particle.string.text = formatInt(obj.points);
}
obj.points = 0; //Ensures that JJ2 won't end up increasing the player's score TWICE, since a call to (the native version of) this function is actually part of the standard pickup-handling code and would otherwise therefore get you in trouble with the FiveUp onObjectHit code.
return true;
}
return false;
}
void onPlayer(jjPLAYER@ play) {
if (jjGameTicks % 350 == 0 && !dragonActivated) jjSample(play.xPos + 128, play.yPos, SOUND::INTRO_MONSTER, play.xPos > 67*32? 32:16, 0);
}
void onMain() {
for (int i = 1; i < jjObjectCount; i++) {
if (jjObjects[i].eventID == OBJECT::BOMBCRATE) {
jjObjects[i].yPos = jjObjects[i].yOrg;
}
}
if (defeated) elapsed++;
if (elapsed == 350) jjNxt("HH17_Ending.j2l", false, false);
}
void onFunction0(jjPLAYER@ play) {
play.activateBoss(true);
if (!dragonActivated) {
dragonActivated = true;
play.showText("@@@@@@@A big, bad dragon blocks your path!", STRING::MEDIUM);
}
}
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.