Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Devan's Revenge (Intro) | sAlAmAnDeR | Single player | 9.6 |
#pragma require "SaLLiB-v2.0.asc"
#pragma require "saldr-common.asc"
#pragma require "saldr-devan.asc"
#include "SaLLiB-v2.0.asc"
#include "saldr-common.asc"
#include "saldr-devan.asc"
void onLevelLoad() {
jjObjectPresets[OBJECT::FISH].determineCurAnim(ANIM::FISH,0);
jjObjectPresets[OBJECT::FISH].determineCurFrame();
jjObjectPresets[OBJECT::DEVILDEVAN].determineCurAnim(ANIM::DEVILDEVAN,5);
jjObjectPresets[OBJECT::DEVILDEVAN].determineCurFrame();
jjObjectPresets[OBJECT::RAVEN].determineCurAnim(ANIM::RAVEN,0);
jjObjectPresets[OBJECT::RAVEN].determineCurFrame();
jjObjectPresets[OBJECT::DEMON].determineCurAnim(ANIM::DEMON,0);
jjObjectPresets[OBJECT::DEMON].determineCurFrame();
jjObjectPresets[OBJECT::BILSY].determineCurAnim(ANIM::BILSBOSS,0);
jjObjectPresets[OBJECT::BILSY].determineCurFrame();
jjObjectPresets[OBJECT::BOLLY].determineCurAnim(ANIM::SONCSHIP,0);
jjObjectPresets[OBJECT::BOLLY].determineCurFrame();
jjObjectPresets[OBJECT::TUFBOSS].determineCurAnim(ANIM::TUFBOSS,0);
jjObjectPresets[OBJECT::TUFBOSS].determineCurFrame();
}
class MiniBollyNPC : BollyNPC {
private INTERPOLATION::Sinusoidal@ siny;
MiniBollyNPC(float xPos, float yPos) {
super(xPos,yPos);
@siny = @INTERPOLATION::Sinusoidal(2,3,jjRandom()%100,65);
spriteScaleX = 0.8;
spriteScaleY = 0.8;
}
void behavior() {
NPC::behavior();
if(jjGameTicks/70%6<2) {
if(jjGameTicks%10==0) {
BollyBullet(xPos+35,yPos+10);
}
}
}
int draw(bool useCustomSpriteProperties=true) const{
float yPos = this.yPos + siny.value(jjGameTicks);
jjDrawRotatedSprite(xPos,yPos,ANIM::SONCSHIP,3,jjGameTicks/7,0,spriteScaleX,spriteScaleY,SPRITE::NORMAL,0,8);
jjDrawRotatedSprite(xPos,yPos-2,ANIM::SONCSHIP,2,jjGameTicks/7,0,spriteScaleX,spriteScaleY,SPRITE::NORMAL,0,8);
jjDrawRotatedSprite(xPos-7,yPos+5,ANIM::SONCSHIP,6,0,0,spriteScaleX,spriteScaleY,SPRITE::NORMAL,0,8);
return -1;
}
}
class BollyBullet : BollyNPC {
BollyBullet(float xPos, float yPos) {
super(xPos, yPos);
jjSample(xPos,yPos,SOUND::SONCSHIP_MISSILE2);
missileAnim();
spriteAngle=576;
moveLinear(118*32,8*32,50);
spriteLayerZ=8;
}
void behavior() {
BollyNPC::behavior();
if(!isMoving()) {
delete();
}
}
}
IRabbitEnemy@ nooblet;
IRabbitEnemy@ catlover;
IRabbitEnemy@ hamburger;
IRabbitEnemy@ socks;
IRabbitEnemy@ roastu;
IRabbitEnemy@ yobo;
DevilDevanNPC@ devan;
array<DemonNPC@> demons;
GAME::Camera@ camera;
void onLevelBegin() {
jjMusicLoad("zombies.it");
MiniBollyNPC(112*32,6*32);
FireAnimatingTile(115*32,9.5*32).spriteLayerZ=8;
FireAnimatingTile(121*32,8*32).spriteLayerZ=8;
FireAnimatingTile(118.5*32,6*32).spriteLayerZ=8;
@nooblet = @IdleRabbitEnemy(CHAR::JAZZ,16.5*32,6*32+13);
nooblet.name = "nooblet";
nooblet.nameLen = 2*32;
nooblet.direction = -1;
@catlover = @CrouchingShootingRabbitEnemy(CHAR::SPAZ,39.5*32,7*32+13);
catlover.name = "CATLOVER";
catlover.nameLen = 2.5*32;
catlover.direction = -1;
catlover.weapon=2;
catlover.fastFire = 10;
catlover.crouch();
catlover.isIdle=true;
@hamburger = @IdleRabbitEnemy(CHAR::LORI,43*32,7*32+13);
hamburger.name = "hamburger";
hamburger.nameLen = 2.5*32;
hamburger.direction = -1;
@socks = @ShootingRabbitEnemy(CHAR::SPAZ,75*32,8*32);
socks.name = "|S|o|C|k|S";
socks.nameLen = 1.5*32;
socks.direction = -1;
socks.hearts = 2;
socks.weapon = 5;
socks.fastFire = 35;
socks.isIdle = true;
@roastu = @CrouchingShootingRabbitEnemy(CHAR::LORI,96*32,5*32+13);
roastu.name = "roastu";
roastu.nameLen = 2*32;
roastu.direction = -1;
roastu.weapon=2;
roastu.fastFire = 10;
roastu.crouch();
roastu.hearts=2;
roastu.isIdle=true;
@yobo = @CrouchingShootingRabbitEnemy(CHAR::SPAZ,94*32,7*32+13);
yobo.name = "YOBOMAN";
yobo.nameLen = 2.5*32;
yobo.direction = 1;
yobo.weapon=2;
yobo.fastFire = 10;
yobo.crouch();
yobo.hearts=2;
yobo.isIdle=true;
@camera = GAME::Camera(jjLocalPlayers[0]);
for(uint i = 0; i < 6; i++) {
DemonNPC@ demon = DemonNPC(6.5*32+i*48,11*32);
demons.insertLast(demon);
}
jjSetFadeColors(255,192,0);
jjPalette.gradient(255, 255, 128, 128, 32, 0, 176, 32);
jjPalette.apply();
@devanPlayer = @DevanShell(jjLocalPlayers[0]);
@CUSTOM::UI = @CUSTOM::EnhancedUI();
CUSTOM::UI.drawLives = false;
CUSTOM::UI.addElement(DevanLivesUI(devanPlayer));
CUSTOM::weapons.registerWeapon(1,devanBlaster,DevanBlasterUI(devanPlayer));
CUSTOM::weapons.registerWeapon(6,devanFireBreath,DevanFireBreathUI(devanPlayer));
jjLocalPlayers[0].morphTo(CHAR::SPAZ);
}
void makeFireballs() {
Firebreath@ fire = @Firebreath(random(31*32,53*32),-2*32,int(random(768+64,1024-128)),40,400);
fire.spriteLayerZ = 7;
fire.direction=1;
float scale = random(1,2);
fire.spriteScaleX = scale;
fire.spriteScaleY = scale;
}
RavenNPC@ makeRaven(float xPos,float yPos) {
float scale = random(0,1);
float y = random(yPos,yPos+15*32);
RavenNPC@ raven = RavenDOA(xPos,y);
raven.direction = 1;
raven.spriteScaleX = scale;
raven.spriteScaleY = scale;
if(scale < .4) raven.spriteLayerZ = 8;
else if(scale < .7) raven.spriteLayerZ = 7;
else raven.spriteLayerZ = 8;
raven.moveLinear(xPos+90*32,y,int(2500-(scale * 1500)));
return raven;
}
RabbitNPC@ makeFlyingRabbit(float xPos, float yPos) {
float scale = random(0,1);
float y = random(yPos,yPos+15*32);
RabbitNPC@ rabbit = @RabbitDOA(getRandomRabbit(),xPos,y);
rabbit.copterAnim();
rabbit.direction = -1;
rabbit.spriteScaleX = scale;
rabbit.spriteScaleY = scale;
if(scale < .4) rabbit.spriteLayerZ = 8;
else if(scale < .7) rabbit.spriteLayerZ = 7;
else rabbit.spriteLayerZ = 8;
rabbit.moveLinear(xPos-17*32,y,int(600-(scale * 300)));
return rabbit;
}
RavenRabbitFight makeFights(float xPos, float yPos) {
return RavenRabbitFight(xPos,yPos);
}
enum RavenState {
CAMERAPANNOOBLET,
NOOBLETDIALOGUE,
ENTER,
ATTACK,
LEAVE,
}
void clearChat() {
for(int i = chat.length()-1; i > -1; i--)
chat.removeAt(i);
}
class RavenAttack : RavenNPC {
private RavenState ravenState = CAMERAPANNOOBLET;
RavenAttack() {
super(24*32,2*32);
spriteLayerZ=8;
scaleLinear(1,2,100);
direction=-1;
nooblet.deleteOnDeath=false;
camera.moveLinear(nooblet.xPos,7.5*32,70);
devanPlayer.allowInput = false;
devanPlayer.xSpeed = 0;
}
void behavior() {
RavenNPC::behavior();
if(ravenState == CAMERAPANNOOBLET) {
if(!camera.isMoving()) {
clearChat();
chat.insertLast(GAME::Speech(nooblet, "|You'll never get away with this Devan!", 11*32));
chat.insertLast(GAME::Speech(nooblet, "|Jazz will save us!", 6*32));
@dialogue = @GAME::DialogueFixedDelay(chat,150);
ravenState = NOOBLETDIALOGUE;
}
} else if(ravenState == NOOBLETDIALOGUE) {
if(!dialogue.isActive) {
ravenState = ENTER;
moveLinear(24*32,2*32,18*32,6*32,100);
}
} else if(ravenState == ENTER) {
if(xPos <21*32)
spriteLayerZ=4;
if(!isMoving()) {
clearChat();
chat.insertLast(GAME::Speech(nooblet, "|AHH!", 1*32));
@dialogue = @GAME::DialogueFixedDelay(chat,100);
ravenState = ATTACK;
nooblet.hurt(5,false);
moveOscillate(COMMON::Position(xPos,yPos),100,16,0,9,HALF_PI);
nooblet.deathAnim();
}
} else if(ravenState == ATTACK) {
if(!isMoving()) {
direction = 1;
nooblet.yPos=nooblet.yPos-12;
moveLinear(24*32,2*32,100);
nooblet.moveLinear(24*32-32,2*32,100);
nooblet.scaleLinear(1,0.5,100);
scaleLinear(2,1,100);
ravenState = LEAVE;
}
} else if(ravenState == LEAVE) {
if(xPos>21*32) {
nooblet.spriteLayerZ = 8;
spriteLayerZ=8;
}
if(!isMoving() && nooblet.yPos>11*32) {
camera.unfreeze();
jjAlert("Raven roasted " + stripPipes(nooblet.name));
nooblet.delete();
delete();
devanPlayer.allowInput = true;
}
}
}
}
class FireAnimatingTile : AnimatingTile {
FireAnimatingTile(float xPos, float yPos) {
array<int> tileIds = {824,825,826,827,828};
super(xPos,yPos,tileIds);
}
void behavior() {
AnimatingTile::behavior();
if(jjGameTicks % 10 == 0) {
makeSmoke(xPos,yPos);
makeSmoke(xPos+10,yPos);
makeSmoke(xPos+20,yPos);
}
}
void makeSmoke(float xPos,float yPos) {
jjPARTICLE@ particle = jjAddParticle(PARTICLE::SMOKE);
particle.xPos = xPos;
particle.yPos = yPos;
}
}
enum FireballState {
CAMERAPAN,
RABBITDIALOGUE,
FIREBALLENTER,
FIREBALLEXPLODE,
CAMERARETURN,
}
class FireballAttack : Fireball {
private FireballState fireState = CAMERAPAN;
FireballAttack() {
super(51*32,1*32);
camera.moveLinear(catlover.xPos,7.5*32,140);
devanPlayer.allowInput = false;
devanPlayer.xSpeed = 0;
}
void behavior() {
Fireball::behavior();
if(fireState == CAMERAPAN) {
if(!camera.isMoving()){
fireState = FireballState::RABBITDIALOGUE;
clearChat();
chat.insertLast(GAME::Speech(catlover,"||He's coming!",3*32));
chat.insertLast(GAME::Speech(hamburger,"||||I'll get the others!",4*32));
@dialogue = GAME::DialogueFixedDelay(chat,140);
}
} else if(fireState == FireballState::RABBITDIALOGUE) {
if(!dialogue.isActive) {
catlover.isIdle = false;
moveLinear(51*32,1*32,41*32,8*32,70);
scaleLinear(1.5,3.5,70);
direction = -1;
fireState = FIREBALLENTER;
}
} else if(fireState == FIREBALLENTER) {
if(!isMoving()) {
playAnimation(ANIM::AMMO,5,0,12,7,false);
fireState = FIREBALLEXPLODE;
hamburger.hurt(5,false);
catlover.hurt(5,false);
FireAnimatingTile(xPos,yPos-28);
FireAnimatingTile(xPos+32,yPos-28);
FireAnimatingTile(xPos-32,yPos-28);
FireAnimatingTile(xPos,yPos-32).moveLinear(47*32,4*32,35);
FireAnimatingTile(xPos,yPos-32).moveLinear(40*32,4*32,35);
FireAnimatingTile(xPos,yPos-32).moveLinear(45*32,11*32,35);
FireAnimatingTile(xPos,yPos-32).moveLinear(35*32,5*32,35);
FireAnimatingTile(xPos,yPos-32).moveLinear(32*32,6*32,35);
camera.moveOscillate(COMMON::Position(camera.xPos,camera.yPos), 70, 0, 8, 8, 0, false);
}
} else if(fireState == FIREBALLEXPLODE) {
if(!camera.isMoving()) {
camera.moveLinear(devanPlayer.xPos,7.5*32,140);
fireState = CAMERARETURN;
}
} else if(fireState == CAMERARETURN) {
if(!camera.isMoving()) {
devanPlayer.allowInput=true;
camera.unfreeze();
delete();
}
}
}
}
class RavenRabbitFight : CUSTOM::Object {
RavenNPC@ raven;
RabbitNPC@ rabbit;
int ravenState = 0;
float fightScale;
int fightTime;
RavenRabbitFight(float xPos, float yPos, int dist=16*32) {
super(NIL, xPos, yPos);
fightScale = random(0.2,0.9);
@raven = @RavenNPC(xPos-(dist/2),yPos);
@rabbit = @RabbitNPC(getRandomRabbit(),xPos+(dist/2),yPos+random(-48,48));
rabbit.copterAnim();
raven.direction = 1;
float maxTime = 600/(16.0*32)*dist;
fightTime = int(maxTime-(fightScale * maxTime/2));
raven.moveLinear(rabbit.xPos,raven.yPos,fightTime);
rabbit.moveLinear(raven.xPos,rabbit.yPos,fightTime);
raven.spriteScaleX = fightScale;
raven.spriteScaleY = fightScale;
rabbit.spriteScaleX = fightScale;
rabbit.spriteScaleY = fightScale;
raven.spriteLayerZ = 8;
rabbit.spriteLayerZ = 8;
}
void behavior() {
float dist = raven.distancePixels(rabbit);
if(dist < 16 && ravenState == 1) {
rabbit.hurtAnim();
rabbit.moveLinear(rabbit.xPos,15*32,100);
ravenState = 2;
} else if(dist < 3*32 && ravenState == 0) {
raven.pose();
raven.moveLinear(rabbit.xPos-32,rabbit.yPos,70);
ravenState = 1;
} else if(!raven.isMoving()) {
raven.moveLinear(xPos+16*32,raven.yPos,fightTime/2+70);
raven.fly();
}
if(ravenState == 1 && !rabbit.isHurtAnim()) rabbit.copterShootAnim();
if(age > 600) {
raven.delete();
rabbit.delete();
delete();
}
}
}
enum State {
INIT,
DIALOGUE,
FREEROAM,
SKYCOLOR,
EPILOGUE
}
State state = INIT;
array<GAME::Speech@> chat;
GAME::Dialogue@ dialogue;
RavenAttack@ ravenAttack = null;
FireballAttack@ fireballAttack = null;
INTERPOLATION::Linear@ rInter;
INTERPOLATION::Linear@ gInter;
INTERPOLATION::Linear@ bInter;
COMMON::Timer@ timer = @COMMON::Timer();
void onFunction0() {
if(ravenAttack is null && nooblet.isActive)
@ravenAttack = @RavenAttack();
}
void onFunction1() {
if(fireballAttack is null)
@fireballAttack = @FireballAttack();
}
void onFunction2() {
if(socks.isActive) socks.isIdle = false;
}
void onFunction3() {
if(roastu.isActive) roastu.isIdle = false;
if(yobo.isActive) yobo.isIdle = false;
}
void onFunction4() {
if(state != SKYCOLOR && state != EPILOGUE) {
state = SKYCOLOR;
timer.start(140);
@rInter = @INTERPOLATION::Linear(255,255,140);
@gInter = @INTERPOLATION::Linear(192,0,140);
}
}
void onMain() {
if(jjGameTicks % 25 == 0) makeFireballs();
if(jjGameTicks % 15 == 0) makeRaven(8*32,0);
if(jjGameTicks % 120 == 0) makeFights(58*32,4*32);
if(jjGameTicks % 25 == 0) makeRaven(68*32,0);
if(jjGameTicks % 140 == 0) makeFlyingRabbit(67*32,0);
if(jjGameTicks % 50 == 0) makeFlyingRabbit(87*32,0);
if(jjGameTicks % 120 == 0) makeFights(75*32,9*32);
if(state == INIT) {
devanPlayer.allowInput = false;
chat.insertLast(GAME::Speech(devanPlayer,"||||||||GO MY MINIONS!",4*32));
chat.insertLast(GAME::Speech(devanPlayer,"||||||||OUR VICTORY IS AT HAND!",7*32));
@dialogue = @GAME::DialogueScaledDelay(chat);
state = DIALOGUE;
} else if(state == DIALOGUE) {
if(!dialogue.isActive) {
for(uint i = 0; i < demons.length; i++) {
demons[i].moveLinear(demons[i].xPos+25*32,demons[i].yPos,250);
demons[i].charge();
devanPlayer.allowInput = true;
}
state = FREEROAM;
}
} else if(state == FREEROAM) {
if(demons.length > 0 && !demons[0].isMoving()) {
for(int i = demons.length-1; i >= 0; i--) {
demons[i].delete();
demons.removeAt(i);
}
}
}
else if(state == SKYCOLOR) {
jjSetFadeColors(int(rInter.value(timer.elapsedTime())),int(gInter.value(timer.elapsedTime())),0);
if(timer.isFinished()) {
state = EPILOGUE;
clearChat();
chat.insertLast(GAME::Speech(devanPlayer,"||||||||And so it comes full circle...",8*32));
chat.insertLast(GAME::Speech(devanPlayer,"||||||||Soon Jazz... Soon...",5.5*32));
@dialogue = GAME::DialogueScaledDelay(chat);
}
} else if(state == EPILOGUE) {
if(!dialogue.isActive) {
jjNxt("saldr7.j2l",false,true);
}
}
devanPlayer.update();
}
//TODO: Fix layering on BG
//TODO: Camera
//TODO: Tile alignment
//TODO: make ravens swirl around the castle
//TODO: Sound, music
//TODO: screen shakes?
//TODO: sky turns red
//TODO: Fix dissapearing ravens
//TODO: outro
//TODO: check SP for object limit
//TODO:Fix/disable sallib warnings
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.