Downloads containing saldr6.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Devan's Revenge (Intro)Featured Download sAlAmAnDeR Single player 9.6 Download file

File preview

#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