Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Anniversary Bash 20 Levels | Jazz2Online | Multiple | N/A |
#include "MLLE-Include-1.4.asc"
const bool MLLESetupSuccessful = MLLE::Setup();
#pragma require "ab20btl07-MLLE-Data-2.j2l"
#pragma require "ab20btl07-MLLE-Data-1.j2l"
#pragma require "ab20btl07.j2l"
#pragma require "SEenergyblast.asc"
#include "SEenergyblast.asc"
#include "weaponMega.asc"
#pragma require "weaponMega.asc"
#pragma require "SEfirework.asc"
#include "SEfirework.asc"
#pragma require "TornadoGun.j2a"
#pragma require "weaponMega.j2a"
void onLevelLoad() {
resetSpread();
ReplaceEggmanAnimation() ;
EnergyBlastEdit energyBlast;
energyBlast.loadAnims(jjAnimSets[ANIM::CUSTOM[0]]);
energyBlast.loadSamples(array<SOUND::Sample> = {SOUND::INTRO_BLOW});
energyBlast.setAsWeapon(4, weaponHook);
se::firework.loadAnims(jjAnimSets[ANIM::CUSTOM[1]]);
se::firework.loadSamples(array<SOUND::Sample> = {SOUND::INTRO_BOEM1, SOUND::INTRO_BOEM2});
se::firework.setAsWeapon(5, weaponHook);
jjObjectPresets[OBJECT::BRIDGE].behavior = Bridge;
jjObjectPresets[OBJECT::CHIPS].scriptedCollisions = true;
jjObjectPresets[OBJECT::CHIPS].behavior = SpreadShot();
jjWeapons[WEAPON::GUN8].spread = SPREAD::NORMAL;
jjObjectPresets[OBJECT::APPLE].behavior = Eggman();
for (int i = 1; i < 255; i++) {
if (jjObjectPresets[i].behavior == BEHAVIOR::PICKUP) {
jjObjectPresets[i].behavior = CannotBeShotDown;
}
}
jjObjectPresets[OBJECT::RFAMMO3].behavior = CannotBeShotDown;
jjObjectPresets[OBJECT::SEEKERAMMO3].behavior = CannotBeShotDown;
jjAnimSets[ANIM::CUSTOM[6]].load(0, "TornadoGun.j2a");
jjAnimations[jjAnimSets[ANIM::AMMO] + 57] = jjAnimations[jjAnimSets[ANIM::CUSTOM[6]] + 3];
jjAnimations[jjAnimSets[ANIM::AMMO] + 56] = jjAnimations[jjAnimSets[ANIM::CUSTOM[6]] + 2];
jjObjectPresets[OBJECT::TOASTERBULLET].behavior = TornadoGun();
jjObjectPresets[OBJECT::TOASTERBULLET].special = jjObjectPresets[OBJECT::TOASTERBULLET].determineCurAnim(ANIM::CUSTOM[6], 0);
jjObjectPresets[OBJECT::TOASTERBULLET].xSpeed = 4;
jjObjectPresets[OBJECT::TOASTERBULLET].counterEnd = 110;
jjObjectPresets[OBJECT::TOASTERBULLET].var[6] = 0;
jjObjectPresets[OBJECT::TOASTERBULLET].freeze = 0;
jjObjectPresets[OBJECT::TOASTERBULLET].eventID = OBJECT::FIREBALLBULLET;
jjObjectPresets[OBJECT::TOASTERBULLET].lightType = jjObjectPresets[OBJECT::FIREBALLBULLET].lightType;
jjObjectPresets[OBJECT::TOASTERBULLET].killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
jjObjectPresets[OBJECT::TOASTERBULLET].lightType = LIGHT::POINT;
jjObjectPresets[OBJECT::TOASTERBULLETPU].behavior = TornadoGunPU();
jjObjectPresets[OBJECT::TOASTERBULLETPU].special = jjObjectPresets[OBJECT::TOASTERBULLETPU].determineCurAnim(ANIM::CUSTOM[6], 1);
jjObjectPresets[OBJECT::TOASTERBULLETPU].xSpeed = 6;
jjObjectPresets[OBJECT::TOASTERBULLETPU].counterEnd = 120;
jjObjectPresets[OBJECT::TOASTERBULLETPU].var[6] = 8;
jjObjectPresets[OBJECT::TOASTERBULLETPU].freeze = 0;
jjObjectPresets[OBJECT::TOASTERBULLETPU].eventID = OBJECT::FIREBALLBULLET;
jjObjectPresets[OBJECT::TOASTERBULLETPU].killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
jjObjectPresets[OBJECT::TOASTERBULLETPU].lightType = LIGHT::POINT2;
jjObjectPresets[OBJECT::TOASTERPOWERUP].determineCurAnim(ANIM::CUSTOM[6], 4);
jjObjectPresets[OBJECT::TOASTERPOWERUP].determineCurFrame();
jjObjectPresets[OBJECT::TOASTERAMMO15].determineCurAnim(ANIM::CUSTOM[6], 5);
jjObjectPresets[OBJECT::TOASTERAMMO15].determineCurFrame();
jjWeapons[WEAPON::TOASTER].defaultSample = false;
jjWeapons[WEAPON::TOASTER].replacedByBubbles = false;
//jjWeapons[WEAPON::TOASTER].spread = SPREAD::NORMAL;
jjWeapons[WEAPON::TOASTER].style = WEAPON::NORMAL;
jjWeapons[WEAPON::TOASTER].multiplier = 1;
}
se::DefaultWeaponHook weaponHook;
bool gameIsActive() {
return jjGameState == GAME::STARTED || jjGameState == GAME::OVERTIME;
}
class EnergyBlastEdit : se::EnergyBlastWeapon {
protected void prepareWeaponProfile(::jjWEAPON@ weapon) const override {
weapon.comesFromBirds = false;
weapon.comesFromBirdsPowerup = false;
weapon.defaultSample = false;
weapon.gradualAim = false;
weapon.multiplier = 6; //was originally 3
weapon.replacedByBubbles = false;
weapon.spread = SPREAD::NORMAL;
weapon.style = WEAPON::POPCORN;
}
}
void CannotBeShotDown(jjOBJ@ obj) {
obj.behave(BEHAVIOR::PICKUP);
if (obj.state == STATE::FLOATFALL) obj.state = STATE::FLOAT;
}
bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
return weaponHook.drawAmmo(player, canvas);
}
uint nextBullet = 200;
int timer = 0;
void onLevelBegin() {
if (!jjIsServer) jjSendPacket(jjSTREAM());
}
void onReceive(jjSTREAM &in packet, int clientID) {
weaponHook.processPacket(packet, clientID);
if (jjIsServer) {
updateTime(clientID);
} else {
int currTime;
packet.pop(currTime);
timer = currTime;
}
}
void updateTime(int clientID) {
jjSTREAM packet;
packet.push(timer);
jjSendPacket(packet, clientID);
}
void onMain() {
weaponHook.processMain();
}
class SpreadShot : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::PICKUP, false);
obj.light = 12;
obj.lightType = LIGHT::BRIGHT;
obj.xPos=obj.xOrg+0*jjSin(-jjGameTicks*5+int(obj.xOrg)*32/3);
obj.yPos=obj.yOrg+0*jjCos(-jjGameTicks*5+int(obj.xOrg)*32/3); }
void onDraw(jjOBJ@ obj) {
jjDrawRotatedSprite(obj.xPos, obj.yPos + 10, ANIM::AMMO, 37, jjGameTicks >> 2, angle, 1, 1, SPRITE::NORMAL, 0, 1);
jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::AMMO, 37, jjGameTicks >> 2, angle, 1, 1, SPRITE::NORMAL, 0, 1);
jjDrawRotatedSprite(obj.xPos, obj.yPos - 10, ANIM::AMMO, 37, jjGameTicks >> 2, angle, 1, 1, SPRITE::NORMAL, 0, 1);
}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ p, int force) {
obj.bulletHandling = HANDLING::IGNOREBULLET;
obj.behavior = BEHAVIOR::EXPLOSION2;
obj.scriptedCollisions = false;
obj.frameID = 0;
if (p.isLocal) spreadShotCountdown = 15;
jjSamplePriority(SOUND::COMMON_PICKUP1);
return true;
}
}
uint spreadShotCountdown = 0;
uint16 angle = 0;
void resetSpread() {
jjWeapons[WEAPON::BLASTER].spread = SPREAD::NORMAL;
jjWeapons[WEAPON::BOUNCER].spread = SPREAD::NORMAL;
jjWeapons[WEAPON::ICE].spread = SPREAD::ICE;
jjWeapons[WEAPON::SEEKER].spread = SPREAD::NORMAL;
jjWeapons[WEAPON::RF].spread = SPREAD::NORMAL;
jjWeapons[WEAPON::TNT].spread = SPREAD::NORMAL;
jjWeapons[WEAPON::TOASTER].spread = SPREAD::NORMAL;
jjWeapons[WEAPON::GUN8].spread = SPREAD::NORMAL;
jjWeapons[WEAPON::GUN9].spread = SPREAD::NORMAL;
}
void onPlayer(jjPLAYER@ p) {
weaponHook.processPlayer(p);
if (spreadShotCountdown > 0 && jjGameTicks % 70 == 0) {
spreadShotCountdown--;
if (spreadShotCountdown == 0) {
resetSpread();
}
}
else if (spreadShotCountdown == 15) {
/* for (uint i = 1; i <= 4; i++) {
jjWeapons[i].spread = SPREAD::RFPU;
}
for (uint i = 7; i <= 9; i++) {
jjWeapons[i].spread = SPREAD::RFPU;
}
jjWeapons[6].spread = SPREAD::RFPU;
*/
jjWeapons[1].spread = SPREAD::RFPU;
jjWeapons[2].spread = SPREAD::RFPU;
jjWeapons[3].spread = SPREAD::RFPU;
jjWeapons[6].spread = SPREAD::RFPU;
jjWeapons[8].spread = SPREAD::RFPU;
jjWeapons[9].spread = SPREAD::RFPU;
}
if (spreadShotCountdown > 0) {
jjTEXTAPPEARANCE normal(STRING::NORMAL);
int x = int(p.cameraX);
int y = int(p.cameraY);
jjDrawSprite(x + jjResolutionWidth - 72, y + jjResolutionHeight - 270, ANIM::PICKUPS, 87, jjGameTicks >> 2, 0, SPRITE::NORMAL, 0, 1);
jjDrawString(x + jjResolutionWidth - 55, y + jjResolutionHeight - 274, "" + spreadShotCountdown, STRING::MEDIUM, normal, 0, SPRITE::PALSHIFT, 0, 1);
}
if (p.health == 0) {
spreadShotCountdown == 0;
resetSpread();
}
angle += 12;
}
void onPlayerInput(jjPLAYER@ player) {
weaponHook.processPlayerInput(player);
}
/*void onReceive(jjSTREAM &in packet, int clientID) {
weaponHook.processPacket(packet, clientID);
}*/
void Bridge(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BRIDGE);
obj.yPos = obj.yOrg - 12;
}
bool LoadWeaponMega3() {
if (!SafeToReplaceWeapon(WEAPON::ICE))
return false;
jjWeapons[WEAPON::ICE].style = WEAPON::POPCORN;
jjWeapons[WEAPON::ICE].spread = SPREAD::TOASTER;
jjWeapons[WEAPON::ICE].multiplier = 12;
jjWeapons[WEAPON::ICE].gradualAim = true;
Preset1.behavior = ApplyIceCloud;
Preset2.behavior = ApplyIceCloud;
Preset1.special = Preset1.determineCurAnim(AnimSet, 0);
Preset2.special = Preset2.determineCurAnim(AnimSet, 0);
Preset1.determineCurFrame(); Preset2.determineCurFrame();
Preset1.isBlastable = true; Preset2.isBlastable = true;
//Preset1.var[6] = Preset1.var[6] | 16; //"fireball"
//Preset2.var[6] = Preset2.var[6] | 16;
Preset1.counterEnd = 100; //lifetime
Preset2.counterEnd = 100;
return true;
}
const bool WeaponMega3Loaded = LoadWeaponMega3();
void ApplyIceCloud(jjOBJ@ obj) { obj.behavior = IceCloud(obj); obj.behave(); }
class IceCloud : WeaponMega {
IceCloud(jjOBJ@ objectOfAttachment) {
@obj = @objectOfAttachment;
obj.xSpeed += obj.var[7] / 65536.f;
if (obj.creatorType == CREATOR::PLAYER)
obj.ySpeed += int(jjPlayers[obj.creatorID].ySpeed) / 2;
obj.state = STATE::FLY;
}
void onBehave(jjOBJ@) override {
obj.xPos += obj.xSpeed *= 0.96;
obj.yPos += obj.ySpeed *= 0.96;
if (obj.frameID < 3 && ++obj.age & 15 == 15) {
++obj.frameID; ++obj.curFrame;
}
if (--obj.counterEnd == 0 || obj.state == STATE::EXPLODE) {
int playerID;
if ( (playerID = getNearestEnemy(400)) >= 0) {
obj.frameID = 0;
obj.killAnim = (obj.curAnim += 1) + 1;
obj.counterEnd = 100;
obj.freeze = 0;
const jjPLAYER@ target = jjPlayers[playerID];
obj.xSpeed = (target.xPos - obj.xPos) / 25;
obj.ySpeed = (target.yPos - obj.yPos) / 25;
obj.xAcc = obj.yAcc = obj.var[7] = 0;
obj.behavior = BEHAVIOR::BULLET;
} else {
obj.counter = 0;
obj.frameID = 0;
obj.curAnim += 2;
obj.behavior = BEHAVIOR::EXPLOSION;
}
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_ICECRUSH);
} else if (jjGameTicks & 1 == 0) {
jjPARTICLE@ part = jjAddParticle(PARTICLE::ICETRAIL);
if (part !is null) {
part.yPos = obj.yPos;
part.xPos = obj.xPos + (jjRandom() & 31) - 15;
}
}
}
void onDraw(jjOBJ@) override {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, 1, SPRITE::TRANSLUCENT);
if (obj.frameID == 3)
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, jjAnimations[obj.curAnim + 1], 0, SPRITE::TRANSLUCENTCOLOR, 15);
}
}
bool LoadWeaponMega4() {
if (!SafeToReplaceWeapon(WEAPON::SEEKER))
return false;
jjWeapons[WEAPON::GUN9].defaultSample = false;
jjWeapons[WEAPON::GUN9].replacedByBubbles = true;
jjObjectPresets[OBJECT::ELECTROBULLET].behavior = ApplyPathfinder;
jjObjectPresets[OBJECT::ELECTROBULLETPU].behavior = ApplyPathfinder;
jjObjectPresets[OBJECT::ELECTROBULLET].special = jjObjectPresets[OBJECT::ELECTROBULLET].determineCurAnim(AnimSet, 0);
jjObjectPresets[OBJECT::ELECTROBULLETPU].special = jjObjectPresets[OBJECT::ELECTROBULLETPU].determineCurAnim(AnimSet, 1);
jjObjectPresets[OBJECT::ELECTROBULLET].determineCurFrame(); jjObjectPresets[OBJECT::ELECTROBULLETPU].determineCurFrame();
jjObjectPresets[OBJECT::ELECTROBULLET].isBlastable = false; jjObjectPresets[OBJECT::ELECTROBULLETPU].isBlastable = false;
jjObjectPresets[OBJECT::ELECTROBULLET].playerHandling = jjObjectPresets[OBJECT::ELECTROBULLETPU].playerHandling = HANDLING::PLAYERBULLET;
jjObjectPresets[OBJECT::ELECTROBULLET].counterEnd = 46; jjObjectPresets[OBJECT::ELECTROBULLETPU].counterEnd = 32;
jjObjectPresets[OBJECT::ELECTROBULLET].var[6] = 16;
return true;
}
const bool WeaponMega4Loaded = LoadWeaponMega4();
void ApplyPathfinder(jjOBJ@ obj) { obj.behavior = Pathfinder(obj); obj.behave(); }
class Pathfinder : WeaponMega {
array<jjOBJ@> nodes;
bool waiting = false;
bool foundAtLeastOneTarget = false;
uint counter = 0;
bool powerup;
Pathfinder(jjOBJ@ objectOfAttachment) {
@obj = @objectOfAttachment;
obj.state = STATE::FLY;
powerup = isPowerup();
jjSample(obj.xPos, obj.yPos, powerup ? SOUND::AMMO_LASER3 : SOUND::AMMO_LASER2);
}
void destroy() {
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_ELECTRIC2);
for (uint i = 0; i < nodes.length; ++i)
nodes[i].delete();
obj.delete();
}
void onBehave(jjOBJ@) override {
if (obj.state == STATE::EXPLODE) {
destroy();
return;
}
obj.frameID = (obj.objectID + jjGameTicks / 3) % 3;
if (++counter >= obj.counterEnd) {
if (waiting = !waiting) { //stop moving
addNode();
counter = obj.counterEnd / 2;
} else { //start moving
if (nodes.length > (uint(powerup ? 6 : 4) / uint(foundAtLeastOneTarget ? 1 : 3)) || obj.state == STATE::DONE) {
destroy();
return;
}
const int nearestEnemyID = getNearestEnemy(200);
if (nearestEnemyID >= 0) {
const jjPLAYER@ target = jjPlayers[nearestEnemyID];
obj.var[7] = 0;
const float standardSpeed = (powerup ? 3.f : 2.5f);
const float dx = target.xPos - obj.xPos, dy = target.yPos - obj.yPos;
foundAtLeastOneTarget = true;
if (abs(dx) > abs(dy)) {
obj.xSpeed = (dx > 0) ? standardSpeed : -standardSpeed;
obj.ySpeed = 0;
} else {
obj.xSpeed = 0;
obj.ySpeed = (dy > 0) ? standardSpeed : -standardSpeed;
}
}
counter = 0;
}
}
if (!waiting) {
obj.xPos += obj.xSpeed + obj.var[7] / 65536.f;
obj.yPos += obj.ySpeed;
if (obj.var[7] > 0x100000)
obj.var[7] = obj.var[7] - 0x80000;
else if (obj.var[7] < -0x100000)
obj.var[7] = obj.var[7] + 0x80000;
if (colliding()) {
counter = obj.counterEnd / 2;
waiting = true;
addNode();
obj.state = STATE::DONE;
}
}
}
bool colliding() const {
return maskedPixelAtBullet() && jjEventAtLastMaskedPixel != AREA::ONEWAY && jjEventAtLastMaskedPixel != AREA::HOOK && jjEventAtLastMaskedPixel != AREA::VINE;
}
void addNode() {
jjOBJ@ node = jjObjects[jjAddObject(OBJECT::BEES, obj.xPos, obj.yPos, obj.creatorID, obj.creatorType)];
node.playerHandling = HANDLING::PLAYERBULLET;
node.var[6] = 2 | (powerup ? 8 : 0) | 16; //fireball
node.animSpeed = powerup ? 2 : 1;
node.curFrame = jjAnimations[obj.curAnim + 2];
node.state = STATE::FLY;
node.lightType = LIGHT::BRIGHT;
node.light = powerup ? 10 : 8;
nodes.insertLast(node);
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_ELECTRIC1);
}
void onDraw(jjOBJ@) override {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame + obj.frameID);
for (uint i = 0; i < nodes.length; ++i) {
const jjOBJ@ node = nodes[i];
const jjOBJ@ node2 = (i < nodes.length - 1) ? nodes[i + 1] : obj;
//jjDrawRectangle(node.xPos, node.yPos, int(node2.xPos - node.xPos) + 1, int(node2.yPos - node.yPos) + 1, 15);
jjDrawSpriteFromCurFrame(node.xPos, node.yPos, node.curFrame + obj.frameID);
}
}
}
class TornadoGun : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BULLET);
jjPLAYER@ creator = jjPlayers[obj.creatorID];
if (obj.state == STATE::FLY) {
if (obj.counter == 1 && creator.isLocal) {
//jjSample(creator.xPos, creator.yPos, SOUND::INTRO_BLOW, 48, 25000);
jjSample(creator.xPos, creator.yPos, SOUND::COMMON_BIRDFLY, 48, 25000);
}
switch (obj.direction) {
case 1: obj.xSpeed = obj.xSpeed - 0.05; obj.ySpeed = obj.ySpeed - 0.1; break;
case -1: obj.xSpeed = obj.xSpeed + 0.05; obj.ySpeed = obj.ySpeed - 0.1; break;
}
float pdx = jjLocalPlayers[0].xPos - obj.xPos, pdy = jjLocalPlayers[0].yPos - obj.yPos;
if ((pdx * pdx + pdy * pdy < 64 * 64) && !creator.isLocal && (jjLocalPlayers[0].team != creator.team || jjFriendlyFire) && gameIsActive()) {
jjLocalPlayers[0].ySpeed -= 2;
jjLocalPlayers[0].xSpeed += 2 * obj.direction;
}
}
if (obj.state == STATE::EXPLODE) {
if (obj.var[0] == 0) {
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_SWISH4, 36, 15000);
obj.var[0] = 1;
}
}
}
}
class TornadoGunPU : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BULLET);
jjPLAYER@ creator = jjPlayers[obj.creatorID];
if (obj.state == STATE::FLY) {
if (obj.counter == 1 && creator.isLocal) {
// jjSample(creator.xPos, creator.yPos, SOUND::INTRO_BLOW, 48, 30000);
jjSample(creator.xPos, creator.yPos, SOUND::COMMON_BIRDFLY, 48, 30000);
}
switch (obj.direction) {
case 1: obj.xSpeed = obj.xSpeed - 0.05; obj.ySpeed = obj.ySpeed - 0.1; break;
case -1: obj.xSpeed = obj.xSpeed + 0.05; obj.ySpeed = obj.ySpeed - 0.1; break;
}
float pdx = jjLocalPlayers[0].xPos - obj.xPos, pdy = jjLocalPlayers[0].yPos - obj.yPos;
if ((pdx * pdx + pdy * pdy < 96 * 96) && !creator.isLocal && (jjLocalPlayers[0].team != creator.team || jjFriendlyFire) && gameIsActive()) {
jjLocalPlayers[0].ySpeed -= 4;
jjLocalPlayers[0].xSpeed += 4 * obj.direction;
}
}
if (obj.state == STATE::EXPLODE) {
if (obj.var[0] == 0) {
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_SWISH4, 36, 15000);
obj.var[0] = 1;
}
}
}
}
bool LoadWeaponMega7() {
if (!SafeToReplaceWeapon(WEAPON::TNT))
return false;
jjWeapons[WEAPON::TNT].defaultSample = false;
jjWeapons[WEAPON::TNT].style = WEAPON::CAPPED;
jjWeapons[WEAPON::TNT].maximum = 18;
Preset1.behavior = function(obj){obj.behavior = GravityWell(obj); obj.behave();};
Preset1.special = Preset1.determineCurAnim(AnimSet, 0);
Preset1.determineCurFrame();
Preset1.state = STATE::IDLE; //why bother with START, really
Preset1.var[6] = 16; //fireball-ish
Preset1.var[6] = 8;
Preset1.animSpeed = 1; //do damage to objects (as opposed to players)
Preset1.counter = 0;
Preset1.xSpeed = 1; //needed to get a direction
Preset1.playerHandling = HANDLING::PLAYERBULLET;
Preset1.eventID = OBJECT::BULLET; //to prevent using /tntdamage
return true;
}
const bool WeaponMega7Loaded = LoadWeaponMega7();
class GravityWell : WeaponMega {
GravityWell(jjOBJ@ objectOfAttachment) {
@obj = @objectOfAttachment;
}
void onBehave(jjOBJ@) override {
obj.frameID = ++obj.counter / 7;
obj.age = jjSampleLooped(obj.xPos, obj.yPos, SOUND::COMMON_MONITOR, obj.age, 63, 5000);
if (obj.counter > 175) {
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_SHLDOF3);
obj.particlePixelExplosion(88);
obj.delete();
} else {
for (uint i = jjObjectCount - 1; i > 0; --i) {
jjOBJ@ other = jjObjects[i];
if (other.isActive && other.eventID <= OBJECT::BULLET && other.isBlastable && other.state != STATE::EXPLODE && (other.creatorType != CREATOR::PLAYER || playerIsEnemy(jjPlayers[other.creator]))) {
float d, dx, dy;
if (withinRange(other.xPos, other.yPos, d, dx, dy)) {
const float angle = atan2(dy, dx);
other.xSpeed += 64 / d * cos(angle);
other.ySpeed += 64 / d * sin(angle);
}
}
}
for (uint i = 0; i < 32; ++i) {
jjPLAYER@ other = jjPlayers[i];
if (other.isInGame && other.blink == 0 && playerIsEnemy(other)) {
float d, dx, dy;
if (withinRange(other.xPos, other.yPos, d, dx, dy)) {
const float angle = atan2(dy, dx);
other.xSpeed += 24 / d * cos(angle);
other.ySpeed += 10 / d * sin(angle);
}
}
}
}
}
void onDraw(jjOBJ@) override {
if (obj.frameID <= 6) {
obj.curFrame = jjAnimations[obj.curAnim] + obj.frameID;
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame);
} else {
while (obj.frameID > 6) obj.frameID -= 3;
obj.curFrame = jjAnimations[obj.curAnim] + obj.frameID;
jjDrawRotatedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, (obj.counter - 7*7) * (obj.xSpeed >= 0 ? -32 : 32));
obj.lightType = LIGHT::RING2;
obj.light = 15 - (obj.counter & 7) * 2;
}
}
bool withinRange(float x, float y, float &out d, float &out dx, float &out dy) const {
dx = obj.xPos - x;
dy = obj.yPos - y;
return (d = sqrt(dx * dx + dy * dy)) < (290);
}
}
class Eggman : jjBEHAVIORINTERFACE {
void onBehave(jjOBJ@ obj) {
float t = (jjGameTicks);
obj.playerHandling = HANDLING::HURT;
obj.xPos = obj.xOrg + 12*32*cos(0.25*t/7+40);
obj.yPos = obj.yOrg + 32*sin(t/7)+32*sin(0.6*t/7+70)+32*sin(0.3*t/7-20);
jjDrawSprite(obj.xPos , obj.yPos , ANIM::PICKUPS, 1, 1, -3*sin(0.25*t/7+40));
}
}
void ReplaceEggmanAnimation() {
jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::APPLE].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 gargoyle(0, 158*32, 2*32, 2*32, 4); //Arguments in order: Leftmost pixel of image in layer; topmost pixel; area width; area height; layer ID (1-indexed). You can check the level for yourself in JCS to see how this matches up with the gargoyle's position in layer 3, although note that JCS uses 1-indexed tile positions, not 0-indexed like AngelScript does.
gargoyle.save(frame);
frame.hotSpotX = -frame.width / 2; //Most hotspot values are negative, and the most common position for a hotspot is in the (negative) center of the frame. That's what this code does.
frame.hotSpotY = -frame.height / 2; //Of course, you're welcome to experiment with other hotspot positions for your own specialized needs, but this is fine for a simple Bee enemy.
}
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.