Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Holiday Hare '18 | SmokeNC | Single player | 8.9 |
#pragma require "HH18E1.j2a"
/*Custom enemies for Holiday Hare 18, by SmokeNC.
I didn't make any of the sprite animation myself and the credits go
to their rightul owners. They were mainly taken from the
Sprites Resource and Sprites-Inc*/
namespace SMOKE {
void POLARBEAR(OBJECT::Object eventID, int hp) {
jjAnimSets[ANIM::CUSTOM[15]].load(0, "HH18E1.j2a");
jjAnimSets[ANIM::CUSTOM[23]].load(5, "HH18E1.j2a");
jjObjectPresets[eventID].behavior = SMOKE::PolarBear();
jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[15], 0);
jjObjectPresets[eventID].counter = 120;
jjObjectPresets[eventID].energy = hp;
jjObjectPresets[eventID].deactivates = false;
}
void SANTAGHOST(OBJECT::Object eventID, int hp) {
jjAnimSets[ANIM::CUSTOM[16]].load(1, "HH18E1.j2a");
jjObjectPresets[eventID].behavior = SMOKE::SantaGhost();
jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[16], 0);
jjObjectPresets[eventID].special = 135;
jjObjectPresets[eventID].energy = hp;
jjObjectPresets[eventID].deactivates = false;
}
void MECHABEAR(OBJECT::Object eventID, int hp) {
jjAnimSets[ANIM::CUSTOM[18]].load(3, "HH18E1.j2a");
jjObjectPresets[eventID].behavior = SMOKE::MechaBear();
jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[18], 0);
jjObjectPresets[eventID].counter = 95;
jjObjectPresets[eventID].energy = hp;
jjObjectPresets[eventID].deactivates = false;
}
void ICEGOLEM(OBJECT::Object eventID, int hp) {
jjAnimSets[ANIM::CUSTOM[17]].load(8, "HH18E1.j2a");
for(int i=0;i<4;i++)
{
jjAnimFrames[jjAnimations[jjAnimSets[ANIM::CUSTOM[17]].firstAnim].firstFrame+i].hotSpotY-=18;
}
jjAnimFrames[jjAnimations[jjAnimSets[ANIM::CUSTOM[17]].firstAnim+1].firstFrame].hotSpotY-=18;
jjObjectPresets[eventID].scriptedCollisions = true;
jjObjectPresets[eventID].playerHandling=HANDLING::SPECIAL;
jjObjectPresets[eventID].behavior = SMOKE::IceGolem();
jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[17], 0);
jjObjectPresets[eventID].counter = 120;
jjObjectPresets[eventID].energy = hp;
jjObjectPresets[eventID].deactivates = false;
}
void FROZENALIEN(OBJECT::Object eventID, int hp) {
jjAnimSets[ANIM::CUSTOM[21]].load(6, "HH18E1.j2a");
jjObjectPresets[eventID].behavior = SMOKE::FrozeAlien();
jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[21], 0);
jjObjectPresets[eventID].counter = 135;
jjObjectPresets[eventID].energy = hp;
jjObjectPresets[eventID].deactivates = false;
}
void FROZENSHADE(OBJECT::Object eventID, int hp) {
jjAnimSets[ANIM::CUSTOM[23]].load(5, "HH18E1.j2a");
jjObjectPresets[eventID].behavior = SMOKE::FrozenShade();
jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[23], 0);
jjObjectPresets[eventID].counter = 120;
jjObjectPresets[eventID].energy = hp;
jjObjectPresets[eventID].deactivates = false;
}
void ICEDRAGON(OBJECT::Object eventID1, OBJECT::Object eventID2) {
jjAnimSets[ANIM::CUSTOM[22]].load(7, "HH18E1.j2a");
jjObjectPresets[eventID1].behavior = SMOKE::IceDrag();
jjObjectPresets[eventID2].behavior = SMOKE::IceDragBody();
jjObjectPresets[eventID2].determineCurAnim(ANIM::CUSTOM[22], 0);
jjObjectPresets[eventID2].energy = 20;
}
void CRYSTALKNIGHT(OBJECT::Object eventID, int hp) {
jjAnimSets[ANIM::CUSTOM[24]].load(9, "HH18E1.j2a");
jjObjectPresets[eventID].behavior = SMOKE::CrystalKnight();
jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[24], 0);
jjObjectPresets[eventID].counter = 110;
jjObjectPresets[eventID].energy = hp;
jjObjectPresets[eventID].deactivates = false;
}
void PENGUINATOR(OBJECT::Object eventID, int hp) {
jjAnimSets[ANIM::CUSTOM[25]].load(2, "HH18E1.j2a");
jjObjectPresets[eventID].behavior = SMOKE::Penguinator();
jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[25], 0);
jjObjectPresets[eventID].counter = 115;
jjObjectPresets[eventID].deactivates = false;
jjObjectPresets[eventID].energy = hp;
}
class Penguinator: jjBEHAVIORINTERFACE {
void onBehave(jjOBJ @ obj) {
int playerID = obj.findNearestPlayer(8000000);
float x = -obj.xPos + jjPlayers[playerID].xPos;
float y = -obj.yPos + jjPlayers[playerID].yPos;
//the bear is initialized with walking phase
if (obj.counter == 139) //stand still
{
obj.xSpeed = +0.001 * int(x) / abs(x);
obj.frameID = 0;
}
if (obj.counter == 140) //attack phase
{
obj.special++;
obj.determineCurAnim(ANIM::CUSTOM[25], 1); //attack animation
if (obj.freeze == 0 && obj.special == 3 * 7) // shoot bullets
{
int bulletID2 = jjAddObject(OBJECT::WATERSHIELDBULLET, obj.xPos, obj.yPos + 10);
jjOBJ @ bull2 = jjObjects[bulletID2];
// bull2.xAcc = 0;
// bull2.xSpeed = obj.direction * 4;
if (bull2.xSpeed * obj.direction < 0)
bull2.xSpeed *= -1;
if (bull2.xAcc * obj.direction < 0)
bull2.xAcc *= -1;
// bull2.yAcc=-0.1;
bull2.playerHandling = HANDLING::ENEMYBULLET;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BLUB1);
}
if (obj.freeze == 0 && obj.special == 4 * 7) // shoot bullets
{
int bulletID2 = jjAddObject(OBJECT::WATERSHIELDBULLET, obj.xPos, obj.yPos + 10);
jjOBJ @ bull2 = jjObjects[bulletID2];
// bull2.xAcc = 0;
// bull2.xSpeed = obj.direction * 4;
if (bull2.xSpeed * obj.direction < 0)
bull2.xSpeed *= -1;
if (bull2.xAcc * obj.direction < 0)
bull2.xAcc *= -1;
// bull2.yAcc=-0.1;
bull2.playerHandling = HANDLING::ENEMYBULLET;
}
if (obj.freeze == 0 && obj.special == 5 * 7) // shoot bullets
{
int bulletID2 = jjAddObject(OBJECT::WATERSHIELDBULLET, obj.xPos, obj.yPos + 10);
jjOBJ @ bull2 = jjObjects[bulletID2];
// bull2.xAcc = 0;
// bull2.xSpeed = obj.direction * 4;
if (bull2.xSpeed * obj.direction < 0)
bull2.xSpeed *= -1;
if (bull2.xAcc * obj.direction < 0)
bull2.xAcc *= -1;
// bull2.yAcc=-0.1;
bull2.playerHandling = HANDLING::ENEMYBULLET;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BLUB1);
}
if(jjDifficulty>=1)
{
if (obj.freeze == 0 && obj.special == 6 * 7) // shoot bullets
{
int bulletID2 = jjAddObject(OBJECT::WATERSHIELDBULLET, obj.xPos, obj.yPos + 10);
jjOBJ @ bull2 = jjObjects[bulletID2];
// bull2.xAcc = 0;
// bull2.xSpeed = obj.direction * 4;
if (bull2.xSpeed * obj.direction < 0)
bull2.xSpeed *= -1;
if (bull2.xAcc * obj.direction < 0)
bull2.xAcc *= -1;
// bull2.yAcc=-0.1;
bull2.playerHandling = HANDLING::ENEMYBULLET;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BLUB1);
}
}
if(jjDifficulty>1)
{
if (obj.freeze == 0 && obj.special == 7 * 7) // shoot bullets
{
int bulletID2 = jjAddObject(OBJECT::WATERSHIELDBULLET, obj.xPos, obj.yPos + 10);
jjOBJ @ bull2 = jjObjects[bulletID2];
// bull2.xAcc = 0;
// bull2.xSpeed = obj.direction * 4;
if (bull2.xSpeed * obj.direction < 0)
bull2.xSpeed *= -1;
if (bull2.xAcc * obj.direction < 0)
bull2.xAcc *= -1;
// bull2.yAcc=-0.1;
bull2.playerHandling = HANDLING::ENEMYBULLET;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BLUB1);
}
}
if (obj.special == 8 * 7 + 1) //end attack phase; start walking phase
{
obj.special = 0;
obj.counter = 0;
obj.xSpeed = 1 * obj.direction;
obj.determineCurAnim(ANIM::CUSTOM[25], 0); //walking animation
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BLUB1);
}
}
if ((obj.special == 0) && (x * x + y * y <= 320 * 320)) // only attack if player is in range
{
if (y < 26)
obj.counter++;
// else obj.counter = 120;
}
//obj.yPos=obj.yOrg;
obj.putOnGround();
obj.behave(BEHAVIOR::WALKINGENEMY, false);
if (obj.state == STATE::FREEZE)
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::FROZEN);
else {
if (obj.justHit == 0) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::NORMAL);
} else
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::SINGLECOLOR, 15);
}
}
}
class PolarBear: jjBEHAVIORINTERFACE {
void onBehave(jjOBJ @ obj) {
int playerID = obj.findNearestPlayer(8000000);
float x = -obj.xPos + jjPlayers[playerID].xPos;
float y = -obj.yPos + jjPlayers[playerID].yPos;
//the bear is initialized with walking phase
if (obj.counter == 139) //stand still
{
obj.xSpeed = +0.01 * int(x) / abs(x);
obj.frameID = 0;
}
if (obj.counter == 140) //attack phase
{
obj.special++;
obj.determineCurAnim(ANIM::CUSTOM[15], 1); //attack animation
if (obj.freeze == 0 && obj.special == 2 * 7 + 4) // shoot bullets
{
int bulletID2 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos + obj.direction * 18, obj.yPos);
jjOBJ @ bull2 = jjObjects[bulletID2];
bull2.determineCurAnim(ANIM::CUSTOM[15], 2);
bull2.xAcc = 0;
bull2.xSpeed = obj.direction * 4.5;
bull2.yAcc = 0;
bull2.ySpeed = 0;
bull2.counterEnd = 50;
bull2.playerHandling = HANDLING::ENEMYBULLET;
bull2.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
int bulletID3 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos + obj.direction * 18, obj.yPos - 5);
jjOBJ @ bull3 = jjObjects[bulletID3];
bull3.determineCurAnim(ANIM::CUSTOM[15], 2);
bull3.xAcc = 0;
bull3.xSpeed = obj.direction * 4.5;
bull3.yAcc = 0;
bull3.ySpeed = -4;
bull3.counterEnd = 50;
bull3.playerHandling = HANDLING::ENEMYBULLET;
bull3.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
jjSample(obj.xPos, obj.yPos, SOUND::INTRO_SWISH3);
}
if (obj.special == 4 * 7 + 1) //end attack phase; start walking phase
{
obj.special = 0;
obj.counter = 0;
obj.xSpeed = 1 * obj.direction;
obj.determineCurAnim(ANIM::CUSTOM[15], 0); //walking animation
}
}
if ((obj.special == 0) && (x * x + y * y <= 320 * 320)) // only attack if player is in range
{
if (y < 26)
obj.counter++;
else obj.counter = 120;
}
obj.behave(BEHAVIOR::WALKINGENEMY, true);
}
}
class GhostBullet : jjBEHAVIORINTERFACE
{
void onBehave(jjOBJ @ obj) {
if(obj.counter==69)
{
obj.xOrg=jjLocalPlayers[0].xPos;
obj.yOrg=jjLocalPlayers[0].yPos;
}
obj.special++;
if (obj.special == 150||obj.state==STATE::KILL)
{
// obj.state = STATE::KILL;
obj.points=0;
obj.particlePixelExplosion(72);
obj.delete();
return;
}
obj.behave(BEHAVIOR::RAPIER, true);
if (obj.state == 13)
obj.state = 8;
obj.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
if (jjLocalPlayers[0].health == 0)
obj.delete();
}
bool onObjectHit(jjOBJ@ obj,jjOBJ@ bullet,jjPLAYER@ player,int force)
{
if (bullet is null) {
player.hurt();
}
return true;
}
}
class SantaGhost: jjBEHAVIORINTERFACE {
bool attack=false;
int counter=0;
void onBehave(jjOBJ @ obj) {
int playerID = obj.findNearestPlayer(8000000);
float x = -obj.xPos + jjPlayers[playerID].xPos;
float y = -obj.yPos + jjPlayers[playerID].yPos;
if (x * x + y * y <= 640 * 640)
{
if(obj.freeze==0 && jjPlayers[playerID].direction*obj.direction>0)
{
obj.xPos+=sin(2 * float(jjGameTicks) / 90) * (12/8)*jjPlayers[playerID].direction;
obj.yPos+=cos(4 * float(jjGameTicks) / 90) * (12/8)*jjPlayers[playerID].direction;
}
}
if(attack==false && obj.freeze==0)
{
obj.determineCurAnim(ANIM::CUSTOM[16], 0);
//obj.counter++;
if (x * x + y * y <= 250 * 250)
counter++;
obj.frameID = (jjGameTicks / 8) % 4;
obj.determineCurFrame();
if (counter >= 140) {
attack=true;
counter = 0;
int bulletID3 = jjAddObject(OBJECT::RAPIER, obj.xPos - obj.direction * 10, obj.yPos - 10, 0, CREATOR::LEVEL);
jjOBJ @ bull3 = jjObjects[bulletID3];
bull3.behavior = SMOKE::GhostBullet();
bull3.direction = -obj.direction;
bull3.state = 8;
bull3.special=0;
bull3.scriptedCollisions=true;
bull3.light=30;
bull3.lightType=LIGHT::LASER;
bull3.bulletHandling = HANDLING::IGNOREBULLET;
bull3.playerHandling=HANDLING::SPECIAL;
obj.points=0;
obj.frameID = 0;
obj.determineCurAnim(ANIM::CUSTOM[16], 1);
obj.determineCurFrame();
jjSample(obj.xPos, obj.yPos, SOUND::RAPIER_GOSTDIE);
}
}
if(attack==true)
{
counter++;
obj.frameID=0;
obj.determineCurFrame();
if (counter >= 30) {
obj.determineCurAnim(ANIM::CUSTOM[16], 0);
attack=false;
counter = 0;
}
}
obj.behave(BEHAVIOR::SPARK,false);
}
void onDraw(jjOBJ @ obj) {
if (obj.state == STATE::FREEZE)
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, +obj.direction, SPRITE::FROZEN,0,1);
else {
if (obj.justHit == 0)
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, +obj.direction, SPRITE::NORMAL,0,1);
else
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, +obj.direction, SPRITE::SINGLECOLOR, 15,1);
}
}
}
class MechaBear: jjBEHAVIORINTERFACE {
void onBehave(jjOBJ @ obj) {
int playerID = obj.findNearestPlayer(8000000);
float x = -obj.xPos + jjPlayers[playerID].xPos;
float y = -obj.yPos + jjPlayers[playerID].yPos;
//the bear is initialized with walking phase
if (obj.counter == 99) //stand still
{
obj.xSpeed = 1 * int(x) / abs(x);
obj.frameID = 0;
}
if (obj.counter == 100) //attack phase
{
obj.special++;
obj.determineCurAnim(ANIM::CUSTOM[18], 1); //attack animation
if (obj.freeze == 0 && obj.special == 1 * 7 + 3) // shoot bullets
{
int bulletID2 = jjAddObject(OBJECT::BOUNCERBULLET, obj.xPos + obj.direction * 18, obj.yPos - 32);
jjOBJ @ bull2 = jjObjects[bulletID2];
bull2.behavior = SMOKE::BigSnowball;
bull2.xAcc = 0;
bull2.xSpeed = obj.direction * ((2 + abs(jjRandom()) % 5));
bull2.yAcc = 0.15;
bull2.ySpeed = -4;
bull2.determineCurAnim(ANIM::CUSTOM[18], 2);
bull2.frameID = 0;
bull2.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
bull2.playerHandling = HANDLING::ENEMYBULLET;
jjSample(obj.xPos, obj.yPos, SOUND::INTRO_SWISH4);
}
if (obj.special == 4 * 7 + 1) //end attack phase; start walking phase
{
obj.special = 0;
obj.counter = 0;
obj.xSpeed = 1 * obj.direction;
obj.determineCurAnim(ANIM::CUSTOM[18], 0); //walking animation
}
}
if ((obj.special == 0) && (x * x + y * y <= 320 * 320)) // only attack if player is in range
obj.counter++;
obj.behave(BEHAVIOR::WALKINGENEMY, false);
obj.yPos = obj.yOrg - 12;
obj.putOnGround();
obj.direction = int((x) / abs(x));
if (obj.state == STATE::FREEZE)
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::FROZEN);
else {
obj.xPos = obj.xOrg;
if (obj.justHit == 0) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::NORMAL);
} else
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::SINGLECOLOR, 15);
}
}
}
void BigSnowball(jjOBJ @ obj) {
if (obj.state != STATE::EXPLODE) {
obj.behave(BEHAVIOR::BOUNCERBULLET, false);
jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[18], 2, 0, jjGameTicks * 60);
} else
obj.behave(BEHAVIOR::BOUNCERBULLET, true);
}
class IceGolem: jjBEHAVIORINTERFACE {
void onBehave(jjOBJ @ obj) {
int playerID = obj.findNearestPlayer(8000000);
float x = -obj.xPos + jjPlayers[playerID].xPos;
float y = -obj.yPos + jjPlayers[playerID].yPos;
if(obj.state==STATE::START)
{
jjPlayers[playerID].boss=obj.objectID;
}
//jjPlayers[playerID].activateBoss();
if (playerID > -1 && obj.freeze == 0) {
if (obj.age > 0) obj.age--;
jjPLAYER@ play;
float dx = jjPlayers[playerID].xPos - obj.xPos, dy = jjLocalPlayers[playerID].yPos - obj.yPos;
if (obj.freeze == 0 && obj.age == 0 && dx * dx + dy * dy < 50 * 50) {
obj.age = 35;
jjPlayers[playerID].xSpeed = 16 * obj.direction;
jjPlayers[playerID].ySpeed = -16 * obj.direction;
jjPlayers[playerID].hurt(1, false);
jjSample(jjPlayers[playerID].xPos, jjPlayers[playerID].yPos, SOUND::FATCHK_HIT1, 42, 0);
}
}
if (obj.state == STATE::KILL)
{
jjTriggers[0] = true;
jjPlayers[playerID].activateBoss(false);
}
if (obj.counter == 139) //stand still
{
obj.xSpeed = +0.001 * int(x) / abs(x);
obj.frameID = 0;
}
if (obj.counter == 140) //attack phase
{
obj.special++;
obj.determineCurAnim(ANIM::CUSTOM[17], 1); //attack animation
if (obj.freeze == 0 && obj.special == 3 * 7) // shoot bullets
{
int bulletID2 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos+obj.direction*26, obj.yPos - 20);
jjOBJ @ bull2 = jjObjects[bulletID2];
bull2.determineCurAnim(ANIM::CUSTOM[17],2);
bull2.behavior=SMOKE::SpikeBall;
bull2.counterEnd=72;
// bull2.xSpeed = obj.direction * 4;
bull2.xSpeed=obj.direction*3;
bull2.ySpeed=-5;
bull2.yAcc=0.15;
bull2.xAcc=0;
// bull2.yAcc=-0.1;
bull2.playerHandling = HANDLING::ENEMYBULLET;
jjSample(obj.xPos, obj.yPos, SOUND::AMMO_ICEGUNPU);
}
if (obj.special == 8 * 7 + 1) //end attack phase; start walking phase
{
obj.special = 0;
obj.counter = 0;
obj.xSpeed = 1 * obj.direction;
obj.determineCurAnim(ANIM::CUSTOM[17], 0); //walking animation
}
}
if ((obj.special == 0) && (x * x + y * y <= 320 * 320)) // only attack if player is in range
{
if (y < 26)
obj.counter++;
else obj.counter = 120;
}
//obj.yPos=obj.yOrg-10;
obj.behave(BEHAVIOR::WALKINGENEMY, false);
// obj.yPos=obj.yOrg-10;
if (obj.state == STATE::FREEZE)
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::FROZEN);
else {
if (obj.justHit == 0) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NORMAL);
} else
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::SINGLECOLOR, 15);
}
if(obj.state==STATE::KILL)
{
obj.particlePixelExplosion(0);
obj.particlePixelExplosion(0);
obj.particlePixelExplosion(0);
obj.delete();
}
}
bool onObjectHit(jjOBJ @ obj, jjOBJ @ bullet, jjPLAYER @ player, int force) { //As described in the signs in-level, this is a nearly 100% faithful recreation of standard enemy collision code.
if (bullet!is null) {
//recreation of HANDLING::HURTBYBULLET with HANDLING::ENEMY
if (obj.causesRicochet) {
if ((bullet.var[6] & 6) == 0) //not fire-based, not a laser beam
bullet.ricochet();
else if ((bullet.var[6] & 4) == 0) //not a laser beam
bullet.delete();
} else if ((bullet.var[6] & 16) == 0) //not a fireball
bullet.state = STATE::EXPLODE;
if (obj.freeze > 0 && force < 3)
force = 3;
obj.energy -= force;
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.
if (obj.energy <= 0) { //killed
obj.energy = 0;
obj.state = STATE::KILL;
if (obj.freeze > 0)
obj.unfreeze(0);
/*else if ((bullet.var[6] & 2) == 0) //not fire-based
obj.particlePixelExplosion(0);
else {
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BURN);
if ((bullet.var[6] & 4) != 0) //laser beam
obj.particlePixelExplosion(72); //gray
else
obj.particlePixelExplosion(((bullet.var[6] & 8) != 0) ? 32 : 40); //powered-up (blue) or not (orange)
}*/
if (player!is null) {
//obj.grantPickup(player, (uint(bullet.curAnim) == jjAnimSets[ANIM::AMMO].firstAnim + 17) ? 5 : 10);
//givePlayerPointsForObject(player, obj);
}
} else
obj.freeze = 0;
} else { //recreation of HANDLING::ENEMY; player guaranteed to be non-null
if (force != 0) { //attacking via special attack, e.g. buttstomp
player.hurt(); //constant amount of damage for special attacks
if (obj.energy <= 0) { //killed
obj.energy = 0;
obj.state = STATE::KILL;
} /*else { //only wounded
obj.justHit = 5;
}*/
if (obj.freeze > 0) {
obj.unfreeze(1);
}
if (force > 0) { //buttstomp or sugar rush
player.buttstomp = 50; //landing
player.ySpeed = player.ySpeed / -2 - 8;
player.yAcc = 0;
player.extendInvincibility(-70);
} else if (force == -101) { //running into frozen enemy
player.xAcc = 0;
player.xSpeed /= -2;
player.ySpeed = -6;
player.extendInvincibility(-10);
}
} else { //not attacking
player.hurt();
}
}
return true;
}
}
void SpikeBall(jjOBJ @ obj) {
obj.behave(BEHAVIOR::BULLET, true);
if (obj.state == STATE::EXPLODE && obj.isActive) {
obj.unfreeze(1);
for (int i = 0; i < 8; i++) {
int bulletID3 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos, obj.yPos, obj.objectID, CREATOR::OBJECT);
jjOBJ @ o = jjObjects[bulletID3];
o.determineCurAnim(ANIM::CUSTOM[17], 3);
o.direction = obj.direction;
o.ySpeed = 6*sin(i*3.141592/4);
o.yAcc=0;
o.xAcc=0;
o.xSpeed = 6 * cos(i*3.141592/4);
o.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
o.playerHandling = HANDLING::ENEMYBULLET;
}
obj.delete();
}
}
//motivated from hh17enemies' ice dragon
class FrozeAlien: jjBEHAVIORINTERFACE {
void onBehave(jjOBJ @ obj) {
int playerID = obj.findNearestPlayer(8000000);
float x = -obj.xPos + jjPlayers[playerID].xPos;
float y = -obj.yPos + jjPlayers[playerID].yPos;
obj.direction = int(x / abs(x));
switch (obj.state) {
case STATE::START:
obj.frameID = (obj.counter / 7) % 3;
obj.determineCurFrame();
obj.putOnGround();
obj.yPos += 6;
obj.special = 138;
obj.state = STATE::IDLE;
break;
case STATE::IDLE:
obj.counter++;
if (x * x + y * y <= 320 * 320)
obj.special++;
else obj.special = 120;
obj.frameID = (obj.counter / 7) % 3;
obj.determineCurFrame();
if (obj.special == 140) {
obj.state = STATE::ATTACK;
obj.special = 0;
obj.frameID = 0;
obj.determineCurAnim(ANIM::CUSTOM[21], 0);
obj.determineCurFrame();
}
break;
case STATE::ATTACK:
obj.determineCurAnim(ANIM::CUSTOM[21], 1);
obj.special++;
obj.counter++;
if (obj.frameID != 2)
obj.frameID = obj.special / 7;
obj.determineCurFrame();
if (obj.special == 16)
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_FLAMER);
if (obj.special > 16 && obj.special % 5 == 1) {
int bulletID3 = jjAddObject(OBJECT::TOASTERBULLET, obj.xPos + obj.direction * 4, obj.yPos + 3, obj.objectID, CREATOR::OBJECT);
jjOBJ @ o = jjObjects[bulletID3];
o.behavior = SMOKE::IceCloud;
o.direction = obj.direction;
o.xSpeed = abs(o.xSpeed) * obj.direction;
o.ySpeed -= 1;
o.curAnim = o.determineCurAnim(ANIM::AMMO, 82, true);
o.freeze = 210;
o.playerHandling = HANDLING::ENEMYBULLET;
}
if (obj.special == 80) {
obj.determineCurAnim(ANIM::CUSTOM[21], 0);
obj.state = STATE::IDLE;
obj.special = 0;
}
break;
case STATE::FREEZE:
if (--obj.freeze == 0) obj.state = obj.oldState;
//consider calling jjOBJ::unfreeze() here
break;
case STATE::DEACTIVATE: //can be left out if level is MP-only
obj.deactivate();
break;
case STATE::KILL: //can be left out if not using normal object energy handling
//obj.particlePixelExplosion();
obj.delete();
break;
}
}
void onDraw(jjOBJ @ obj) {
obj.draw();
}
}
void IceCloud(jjOBJ @ obj) {
obj.behave(BEHAVIOR::TOASTERBULLET, true);
int playerID = obj.findNearestPlayer(30000);
if (obj.state == STATE::FLY && obj.doesCollide(jjPlayers[playerID], true)) {
jjPlayers[playerID].freeze(true);
jjPlayers[playerID].xSpeed -= (obj.xSpeed / (obj.direction == -1 ? 8 : -8)) * obj.direction;
}
}
class IceDragBody: jjBEHAVIORINTERFACE {
void onBehave(jjOBJ @ obj) {
int playerID = obj.findNearestPlayer(30000);
float x = -obj.xPos + jjPlayers[playerID].xPos;
float y = -obj.yPos + jjPlayers[playerID].yPos;
float t = float(jjGameTicks) / 30;
obj.yPos = obj.yOrg + 50 * sin(t) * sin((2 + sin(t - 3.14 / 2)) * (obj.xAcc / 80));
switch (obj.state) {
case STATE::START:
obj.determineCurFrame();
obj.state = STATE::FLOAT;
break;
case STATE::FLOAT:
obj.determineCurFrame();
if (obj.creatorID != uint(obj.var[0])) // dragon head
{
obj.xPos = obj.xOrg - 8 * (20 - obj.energy) * obj.direction;
obj.xAcc = obj.special - (8 * (20 - obj.energy) * obj.direction);
if (obj.counter < 130)
obj.counter++;
if (obj.counter >= 130) {
if (obj.frameID != 5)
obj.frameID = int((obj.counter - 130) / 7);
obj.determineCurFrame();
obj.counter++;
}
if (obj.counter >= 130 + 6 * 6 && obj.counter%10==0) {
jjSample(obj.xPos, obj.yPos, SOUND::DEVILDEVAN_DRAGONFIRE);
int bulletID3 = jjAddObject(OBJECT::FIRESHIELDBULLET, obj.xPos + obj.direction * 4, obj.yPos + 3, obj.objectID, CREATOR::OBJECT);
jjOBJ @ o = jjObjects[bulletID3];
o.direction = -1;
o.xAcc = 0;
o.xSpeed = 5 * obj.direction;
o.animSpeed=1;
// o.ySpeed = 2;
// o.determineCurAnim(ANIM::CUSTOM[22], 3);
//o.determineCurAnim(ANIM::CUSTOM[24], 2);
o.playerHandling = HANDLING::ENEMYBULLET;
o.counterEnd = 50;
// o.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
}
if (obj.counter == 130 + 15 * 7) {
obj.frameID = 0;
obj.counter = 0;
}
if (obj.direction == -1 && obj.xAcc >= -8)
obj.state = STATE::KILL;
else if (obj.direction == 1 && obj.xAcc <= 8)
obj.state = STATE::KILL;
} else { // dragon bodyparts
if (obj.ySpeed <= 20 - jjObjects[obj.creatorID].energy)
obj.delete();
else if (obj.energy < 20) {
jjObjects[obj.creatorID].energy -= 1;
obj.energy = 20;
}
}
if (obj.doesCollide(jjPlayers[playerID], true) || x * x + y * y < 32 * 32) {
// jjPlayers[playerID].freeze(true);
jjPlayers[playerID].xSpeed += 16 * obj.direction;
jjPlayers[playerID].hurt(1, false);
}
break;
case STATE::FREEZE:
obj.unfreeze(0);
obj.state = obj.oldState;
//consider calling jjOBJ::unfreeze() here
break;
case STATE::DEACTIVATE: //can be left out if level is MP-only
obj.deactivate();
break;
case STATE::KILL: //can be left out if not using normal object energy handling
//obj.particlePixelExplosion();
obj.particlePixelExplosion(2);
obj.delete();
break;
}
}
void onDraw(jjOBJ @ obj) {
if(obj.creatorID != uint(obj.var[0]))
{
if (obj.justHit == 0) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::NORMAL,0,3);
} else
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::SINGLECOLOR, 15,3);
}
else {
if (obj.justHit == 0) {
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::NORMAL);
} else
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, -obj.direction, SPRITE::SINGLECOLOR, 15);
}
}
}
// I used lots of class instances without their real meaning here, forgive me for that
class IceDrag: jjBEHAVIORINTERFACE {
void onBehave(jjOBJ @ obj) {
if (obj.state == STATE::START) {
if (jjMaskedPixel(int(obj.xPos + 32), int(obj.yPos)) == true)
obj.direction = -1;
else obj.direction = 1;
int DragHead = jjAddObject(OBJECT::CRAB, obj.xPos + 8 * 19 * obj.direction - ((19 == 19 ? (-5) : 0) + (19 > 0 ? (-3) : 0)) * obj.direction, obj.yPos, obj.objectID, CREATOR::OBJECT);
jjOBJ @ oo = jjObjects[DragHead];
oo.determineCurAnim(ANIM::CUSTOM[22], 0);
oo.frameID = 0;
oo.direction = obj.direction;
oo.deactivates = false;
oo.counter = 0;
oo.behavior = SMOKE::IceDragBody();
int temp=int(oo.xAcc);
oo.special = temp= 8 * 19 * obj.direction + ((19 == 19 ? (5) : 0) + (19 > 0 ? (3) : 0)) * obj.direction;
oo.yAcc = oo.xPos;
for (int i = 0; i < 19; i++) {
int DragBody = jjAddObject(OBJECT::CRAB, obj.xPos + 8 * i * obj.direction + (i > -1 ? (3) : 0) * obj.direction, obj.yPos, DragHead, CREATOR::OBJECT);
jjOBJ @ o = jjObjects[DragBody];
o.behavior = SMOKE::IceDragBody();
if (i == 0) {
o.frameID = 0;
o.determineCurAnim(ANIM::CUSTOM[22], 1);
}
if (i > 0 && i < 19) {
o.frameID = 0;
o.determineCurAnim(ANIM::CUSTOM[22], 1);
}
o.direction = obj.direction;
o.special = o.xAcc = 8 * i * obj.direction + (i > 0 ? (3) : 0) * obj.direction;
o.yAcc = obj.xPos;
o.ySpeed = 18 - i + 1;
o.var[0] = DragHead;
o.isBlastable = false;
o.deactivates = false;
}
obj.state = STATE::KILL;
} else obj.delete();
}
}
class FrozenShade: jjBEHAVIORINTERFACE {
void onBehave(jjOBJ @ obj) {
int playerID = obj.findNearestPlayer(8000000);
float x = -obj.xPos + jjPlayers[playerID].xPos;
float y = -obj.yPos + jjPlayers[playerID].yPos;
obj.direction = int(x / abs(x));
switch (obj.state) {
case STATE::START:
obj.determineCurAnim(ANIM::CUSTOM[23], 0);
obj.special = 80;
obj.state = STATE::IDLE;
break;
case STATE::IDLE:
obj.counter++;
obj.xPos = obj.xOrg + sin(2 * float(obj.counter) / 90) * 16;
obj.yPos = obj.yOrg + cos(2 * float(obj.counter) / 90) * 16;
if (x * x + y * y <= 400 * 400)
obj.special++;
obj.frameID = (obj.counter / 7) % 4;
obj.determineCurFrame();
if (obj.special == 140) {
obj.state = STATE::ATTACK;
obj.special = 0;
obj.frameID = 0;
obj.determineCurAnim(ANIM::CUSTOM[23], 1);
obj.determineCurFrame();
}
break;
case STATE::ATTACK:
// obj.determineCurAnim(ANIM::CUSTOM[21], 1);
obj.special++;
// obj.counter++;
obj.frameID = obj.special / 7;
obj.determineCurFrame();
if (obj.special == 7 * 5 + 4) {
jjSample(obj.xPos, obj.yPos, SOUND::AMMO_ICEPU2, 90);
for (int i = -1; i < 2; i++) {
int bulletID3 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos + obj.direction * 15, obj.yPos-8, obj.objectID, CREATOR::OBJECT);
jjOBJ @ o = jjObjects[bulletID3];
o.determineCurAnim(ANIM::CUSTOM[23], 3);
o.direction = obj.direction;
o.xSpeed = 0 * obj.direction;
o.xAcc = obj.direction * 0.11;
o.yAcc=0;
o.counterEnd=60;
o.ySpeed = 2 * i;
o.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
o.playerHandling = HANDLING::ENEMYBULLET;
}
}
if (obj.special == 10 * 7 - 1) {
obj.determineCurAnim(ANIM::CUSTOM[23], 0);
obj.state = STATE::IDLE;
obj.special = 0;
}
break;
case STATE::FREEZE:
if (--obj.freeze == 0) obj.state = obj.oldState;
//consider calling jjOBJ::unfreeze() here
break;
case STATE::DEACTIVATE: //can be left out if level is MP-only
obj.deactivate();
break;
case STATE::KILL: //can be left out if not using normal object energy handling
//obj.particlePixelExplosion();
obj.delete();
break;
}
}
void onDraw(jjOBJ @ obj) {
obj.draw();
}
}
enum KangarooVariables {
kvWIDTH = 0, kvHEIGHT, kvMINX, kvMAXX, kvMINY, kvMAXY, kvJUMPDELAY, kvMINDISTANCE, kvGLOVE1FRAME, kvGLOVE2FRAME, kvSECONDSTAGE
}
//credts to violetCLM
jjOBJ @ SNOWMAN(uint8 eventID, int minX = 0, int maxX = 4, int minY = 6, int maxY = 12, int jumpDelay = 35, int minDistance = 224, int hp = 3) {
//Kangaroo::Private::loadAnims();
jjAnimSets[ANIM::CUSTOM[19]].load(4, "HH18E1.j2a");
jjOBJ @ preset = jjObjectPresets[eventID];
preset.behavior = Snowman;
preset.state=STATE::START;
preset.frameID = 0;
preset.determineCurFrame();
preset.determineCurAnim(ANIM::CUSTOM[19], 0);
SMOKE::applyGenericEnemySettingsToPreset(preset);
preset.deactivates = true;
preset.energy = hp;
preset.points = 200;
preset.yAcc = 0.33f;
preset.counter = 0;
preset.var[kvWIDTH] = 12;
preset.var[kvHEIGHT] = 28;
preset.var[kvMINX] = minX;
preset.var[kvMAXX] = maxX;
preset.var[kvMINY] = minY;
preset.var[kvMAXY] = maxY;
preset.var[kvJUMPDELAY] = jumpDelay;
preset.var[kvMINDISTANCE] = minDistance;
preset.age=0;
return preset;
}
//thanks VioletCLM
void Snowman(jjOBJ @ obj) {
float X = jjLocalPlayers[0].xPos - obj.xPos;
float Y = jjLocalPlayers[0].yPos - obj.yPos;
const int width = obj.var[kvWIDTH];
const int height = obj.var[kvHEIGHT];
switch (obj.state) {
case STATE::START:
obj.state = STATE::IDLE;
SMOKE::putEnemyOnGround(obj);
case STATE::IDLE:
SMOKE::putEnemyOnGround(obj);
if(obj.frameID!=2)
obj.frameID=obj.age/14;
if (obj.counter <= 0 || --obj.counter == 0) {
const int nearestPlayerID = obj.findNearestPlayer(int(pow(obj.var[kvMINDISTANCE], 2)));
if (nearestPlayerID >= 0) {
obj.age++;
jjPLAYER @ nearestPlayer = jjPlayers[nearestPlayerID];
obj.xSpeed = (nearestPlayer.xPos - obj.xPos) / 20.0f;
obj.direction = (obj.xSpeed >= 0) ? 1 : -1;
float xSpeed = abs(obj.xSpeed);
if (xSpeed > obj.var[kvMAXX]) xSpeed = obj.var[kvMAXX];
else if (xSpeed < obj.var[kvMINX]) xSpeed = obj.var[kvMINX];
obj.xSpeed = xSpeed * obj.direction;
float ySpeed = abs((nearestPlayer.yPos - obj.yPos) / 20.0f);
if (ySpeed > obj.var[kvMAXY]) ySpeed = obj.var[kvMAXY];
else if (ySpeed < obj.var[kvMINY]) ySpeed = obj.var[kvMINY];
obj.ySpeed = -ySpeed;
if(obj.age==49)
{
obj.ySpeed=-8;
obj.state = STATE::JUMP;
obj.counter = obj.var[kvJUMPDELAY];
jjSample(obj.xPos, obj.yPos, ((jjRandom() & 1) == 0) ? SOUND::BUBBA_BUBBABOUNCE1 : SOUND::BUBBA_BUBBABOUNCE2);
}
} else
obj.direction = (obj.xPos > jjLocalPlayers[0].xPos) ? -1 : 1;
}
if (jjLocalPlayers[0].specialMove != 0 && (X * X + Y * Y < 300 * 300)) {
obj.ySpeed = -8;
obj.xSpeed = obj.var[kvMINY] * obj.direction;
obj.state = STATE::JUMP;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_JUMP);
}
obj.determineCurFrame();
break;
case STATE::FREEZE:
if (obj.freeze > 0)
--obj.freeze;
if (obj.freeze <= 0) {
obj.state = obj.oldState;
obj.unfreeze(0);
}
break;
case STATE::JUMP:
{
obj.yPos += (obj.ySpeed += obj.yAcc);
const int newXPos = int(obj.xPos + obj.xSpeed) + (width * obj.direction) / 2;
if ((newXPos < 0) || (newXPos > jjLayerWidth[4] * 32) || jjMaskedVLine(newXPos, int(obj.yPos - height / 2), height)) {
obj.xSpeed = -obj.xSpeed;
obj.direction = -obj.direction;
}
obj.xPos += obj.xSpeed;
int newYPos = int(obj.yPos + obj.ySpeed);
if (obj.ySpeed < 0) {
if ((newYPos < 0) || jjMaskedHLine(int(obj.xPos) - width / 2, width, newYPos - height / 2)) {
obj.ySpeed = obj.yAcc;
obj.frameID = 2;
} else obj.frameID = 1;
}
if (obj.ySpeed > 0) {
if ((newYPos > jjLayerHeight[4] * 32) || jjMaskedHLine(int(obj.xPos) - width / 2, width, newYPos + height / 2)) {
obj.state = STATE::DUCK;
// obj.yPos-=2;
obj.ySpeed = 0;
obj.frameID = 0;
obj.counter = 0;
obj.xSpeed = 7 * obj.direction;
SMOKE::putEnemyOnGround(obj);
} else obj.frameID = 2;
}
obj.determineCurFrame();
break;
}
case STATE::DUCK:
{
if (obj.xSpeed > 0 && abs(obj.xSpeed) > 0.1)
obj.xSpeed -= 0.07;
if (obj.xSpeed < 0 && abs(obj.xSpeed) > 0.1)
obj.xSpeed += 0.07;
if (abs(obj.xSpeed) < 0.1)
obj.xSpeed = 0;
if (obj.xSpeed > 0)
obj.direction = 1;
else obj.direction = -1;
obj.determineCurAnim(ANIM::CUSTOM[19], 2);
obj.frameID = int((jjGameTicks / 7) % 4);
//obj.yPos += (obj.ySpeed += obj.yAcc);
const int newXPos = int(obj.xPos + obj.xSpeed) + (width * obj.direction) / 2;
if ((newXPos < 0) || (newXPos > jjLayerWidth[4] * 32) || jjMaskedVLine(newXPos, int(obj.yPos - height / 2) - 2, height - 8)) {
obj.xSpeed = -obj.xSpeed;
if (obj.xSpeed != 0)
obj.direction = -obj.direction;
}
obj.xPos += obj.xSpeed;
int newYPos = int(obj.yPos + obj.ySpeed);
if (obj.ySpeed < 0) {
if ((newYPos < 0) || jjMaskedHLine(int(obj.xPos) - width / 2, width, newYPos - height / 2)) {
obj.ySpeed = obj.yAcc;
}
}
if ((newYPos > jjLayerHeight[4] * 32) || jjMaskedHLine(int(obj.xPos) - width / 2, width, newYPos + height / 2)) {
obj.special = 0;
obj.counter++;
} else {
obj.special++;
obj.yPos += obj.special * obj.yAcc;
}
obj.determineCurFrame();
if (obj.counter == 100) {
obj.frameID = 0;
obj.age=0;
obj.state = STATE::IDLE;
obj.counter = obj.var[kvJUMPDELAY];
obj.determineCurAnim(ANIM::CUSTOM[19], 0);
}
break;
}
case STATE::DEACTIVATE:
obj.deactivate();
return;
case STATE::KILL:
obj.delete();
return;
}
obj.draw();
}
void putKangarooOnGround(jjOBJ @ obj, int width, int height) {
while (!jjMaskedHLine(int(obj.xPos) - width / 2, width, int(obj.yPos) + height / 1))
obj.yPos += 1;
}
void putEnemyOnGround(jjOBJ @ obj) {
int width=jjAnimFrames[obj.curFrame].width;
int height=jjAnimFrames[obj.curFrame].height;
int hotY=jjAnimFrames[obj.curFrame].hotSpotY;
while (!jjMaskedHLine(int(obj.xPos) - width / 2, width, int(obj.yPos) + height + hotY))
obj.yPos += 1;
// while (jjMaskedHLine(int(obj.xPos) - width / 2, width, int(obj.yPos) + height + hotY))
// obj.yPos -= 1;
}
void liftEnemyFromGround(jjOBJ @ obj) {
int width=jjAnimFrames[obj.curFrame].width;
int height=jjAnimFrames[obj.curFrame].height;
int hotY=jjAnimFrames[obj.curFrame].hotSpotY;
while (jjMaskedHLine(int(obj.xPos) - width / 2, width, int(obj.yPos) + height + hotY))
obj.yPos -= 1;
}
void applyGenericEnemySettingsToPreset(jjOBJ @ preset) {
preset.playerHandling = HANDLING::ENEMY;
preset.bulletHandling = HANDLING::HURTBYBULLET;
preset.causesRicochet = false;
preset.isBlastable = false;
preset.triggersTNT = true;
preset.isFreezable = true;
preset.isTarget = true;
preset.scriptedCollisions = false;
preset.direction = 1;
preset.freeze = 0;
}
class CrystalKnight : jjBEHAVIORINTERFACE{
float angle;
void onBehave(jjOBJ @ obj) {
int playerID = obj.findNearestPlayer(8000000);
float x = -obj.xPos + jjPlayers[playerID].xPos;
float y = -obj.yPos + jjPlayers[playerID].yPos;
switch (obj.state) {
case STATE::START:
obj.direction = 1;
obj.state = STATE::FLOAT;
break;
case STATE::FLOAT:
obj.counter++;
/*if (x * x + y * y <= 320 * 320)
obj.special++;*/
obj.frameID = (jjGameTicks / 7) % 3;
obj.determineCurFrame();
for (int i = 0; i < jjLocalPlayerCount; i++) {
jjPLAYER @ p = jjLocalPlayers[i];
if (obj.xPos < p.xPos) {
obj.direction = 1;
}
if (obj.xPos > p.xPos) {
obj.direction = -1;
}
}
if (x * x + y * y <= (10+jjDifficulty)*32* (10+jjDifficulty)*32)
{
obj.special++;
angle= atan2((obj.yPos - jjPlayers[playerID].yPos), (obj.xPos- jjPlayers[playerID].xPos));
obj.xPos -=cos(angle)*2+sin(jjGameTicks/20);
obj.yPos -=sin(angle)*2+sin(jjGameTicks/10);
}
else
{
obj.xPos+=sin(2 * float(jjGameTicks) / 90) * (12/8);
obj.yPos+=2*cos(7 * float(jjGameTicks) / 90) * (12/8);
}
if (obj.special == 120) {
obj.state = STATE::ATTACK;
obj.special = 0;
obj.determineCurFrame();
obj.determineCurAnim(ANIM::CUSTOM[24], 1);
}
break;
case STATE::ATTACK:
if(obj.frameID<5)
obj.frameID = (obj.special / 5) ;
obj.determineCurFrame();
obj.special++;
//obj.counter++;
if (obj.special == 4*6) {
for(int i=-1;i<2;i+=1)
{
int bulletID3 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos + obj.direction * 34, obj.yPos - 10);
jjOBJ @ bull3 = jjObjects[bulletID3];
bull3.behavior = SMOKE::CrystalBall();
bull3.state=STATE::START;
bull3.determineCurAnim(ANIM::CUSTOM[24], 2);
bull3.playerHandling = HANDLING::ENEMYBULLET;
bull3.xAcc=bull3.yAcc=0;
bull3.special=i;
bull3.counter=0;
bull3.counterEnd=200;
bull3.killAnim=jjAnimSets[ANIM::AMMO].firstAnim+82;
// bull3.killAnim=jjObjectPresets[OBJECT::PLASMASHIELDBULLET].killAnim;
obj.determineCurFrame();
obj.determineCurAnim(ANIM::CUSTOM[24], 1);
jjSample(obj.xPos, obj.yPos, SOUND::AMMO_ICEPU4);
}
}
if (obj.special == 8*6) {
obj.determineCurAnim(ANIM::CUSTOM[24], 0);
obj.state = STATE::FLOAT;
obj.special = 0;
}
break;
case STATE::FREEZE:
if (--obj.freeze == 0) obj.state = obj.oldState;
//consider calling jjOBJ::unfreeze() here
break;
case STATE::DEACTIVATE: //can be left out if level is MP-only
obj.deactivate();
break;
case STATE::KILL: //can be left out if not using normal object energy handling
//obj.particlePixelExplosion();
obj.delete();
break;
}
}
void onDraw(jjOBJ @ obj) {
obj.draw();
}
}
class CrystalBall :jjBEHAVIORINTERFACE{
float angle;
void onBehave(jjOBJ @ obj) {
int targetID = 0;
if(obj.counter==0)
angle= atan2((obj.yOrg - jjPlayers[targetID].yPos), (obj.xOrg- jjPlayers[targetID].xPos));
obj.xSpeed=(-cos(angle)-sin(angle)*obj.special*2*cos(float(2*obj.counter)/20))*3;
obj.ySpeed=(-sin(angle)+cos(angle)*obj.special*2*cos(float(2*obj.counter)/20))*3;
obj.behave(BEHAVIOR::BULLET, true);
}
}
jjOBJ @ SNOWMAN2(uint8 eventID, int minX = 0, int maxX = 4, int minY = 6, int maxY = 12, int jumpDelay = 35, int minDistance = 224, int hp = 3) {
//Kangaroo::Private::loadAnims();
jjAnimSets[ANIM::CUSTOM[26]].load(10, "HH18E1.j2a");
jjOBJ @ preset = jjObjectPresets[eventID];
preset.behavior = Snowman2;
preset.frameID = 0;
preset.determineCurFrame();
preset.determineCurAnim(ANIM::CUSTOM[26],0);
SMOKE::applyGenericEnemySettingsToPreset(preset);
preset.deactivates = true;
preset.energy = hp;
preset.points = 200;
preset.yAcc = 0.33f;
preset.counter = 0;
preset.var[kvWIDTH] = 12;
preset.var[kvHEIGHT] = 28;
preset.var[kvMINX] = minX;
preset.var[kvMAXX] = maxX;
preset.var[kvMINY] = minY;
preset.var[kvMAXY] = maxY;
preset.var[kvJUMPDELAY] = jumpDelay;
preset.var[kvMINDISTANCE] = minDistance;
return preset;
}
void Snowman2(jjOBJ @ obj) {
float X = jjLocalPlayers[0].xPos - obj.xPos;
float Y = jjLocalPlayers[0].yPos - obj.yPos;
const int width = obj.var[kvWIDTH];
const int height = obj.var[kvHEIGHT];
switch (obj.state) {
case STATE::START:
obj.state = STATE::IDLE;
SMOKE::putEnemyOnGround(obj);
case STATE::IDLE:
SMOKE::putEnemyOnGround(obj);
if(obj.frameID!=2)
obj.frameID=obj.age/14;
if (obj.counter <= 0 || --obj.counter == 0) {
const int nearestPlayerID = obj.findNearestPlayer(int(pow(obj.var[kvMINDISTANCE], 2)));
if (nearestPlayerID >= 0) {
obj.age++;
jjPLAYER @ nearestPlayer = jjPlayers[nearestPlayerID];
obj.xSpeed = (nearestPlayer.xPos - obj.xPos) / 20.0f;
obj.direction = (obj.xSpeed >= 0) ? 1 : -1;
float xSpeed = abs(obj.xSpeed);
if (xSpeed > obj.var[kvMAXX]) xSpeed = obj.var[kvMAXX];
else if (xSpeed < obj.var[kvMINX]) xSpeed = obj.var[kvMINX];
obj.xSpeed = xSpeed * obj.direction;
float ySpeed = abs((nearestPlayer.yPos - obj.yPos) / 20.0f);
if (ySpeed > obj.var[kvMAXY]) ySpeed = obj.var[kvMAXY];
else if (ySpeed < obj.var[kvMINY]) ySpeed = obj.var[kvMINY];
obj.ySpeed = -ySpeed;
if(obj.age==49)
{
obj.ySpeed=-10;
obj.state = STATE::JUMP;
obj.counter = obj.var[kvJUMPDELAY];
jjSample(obj.xPos, obj.yPos, ((jjRandom() & 1) == 0) ? SOUND::BUBBA_BUBBABOUNCE1 : SOUND::BUBBA_BUBBABOUNCE2);
}
} else
obj.direction = (obj.xPos > jjLocalPlayers[0].xPos) ? -1 : 1;
}
if (jjLocalPlayers[0].specialMove != 0 && (X * X + Y * Y < 300 * 300)) {
obj.ySpeed = -8;
obj.xSpeed = obj.var[kvMINY] * obj.direction;
obj.state = STATE::JUMP;
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_JUMP);
}
obj.determineCurFrame();
break;
case STATE::FREEZE:
if (obj.freeze > 0)
--obj.freeze;
if (obj.freeze <= 0) {
obj.state = obj.oldState;
obj.unfreeze(0);
}
break;
case STATE::JUMP:
{
obj.counter++;
obj.yPos += (obj.ySpeed += obj.yAcc);
const int newXPos = int(obj.xPos + obj.xSpeed) + (width * obj.direction) / 2;
if ((newXPos < 0) || (newXPos > jjLayerWidth[4] * 32) || jjMaskedVLine(newXPos, int(obj.yPos - height / 2), height)) {
obj.xSpeed = -obj.xSpeed;
obj.direction = -obj.direction;
}
obj.xPos += obj.xSpeed;
int newYPos = int(obj.yPos + obj.ySpeed);
if (obj.ySpeed < 0) {
if ((newYPos < 0) || jjMaskedHLine(int(obj.xPos) - width / 2, width, newYPos - height / 2)) {
obj.ySpeed = obj.yAcc;
obj.frameID = 2;
} else obj.frameID = 1;
}
if (obj.ySpeed > 0) {
if ((newYPos > jjLayerHeight[4] * 32) || jjMaskedHLine(int(obj.xPos) - width / 2, width, newYPos + height / 2)) {
obj.state = STATE::FIRE;
// obj.yPos-=2;
obj.ySpeed = 0;
obj.frameID = 0;
obj.counter = 1;
obj.xSpeed = 7 * (jjLocalPlayers[0].xPos - obj.xPos) / abs((jjLocalPlayers[0].xPos - obj.xPos));
SMOKE::putEnemyOnGround(obj);
} else obj.frameID = 2;
}
obj.determineCurFrame();
if(obj.counter%20==0)
{
int bulletID2 = jjAddObject(OBJECT::BLASTERBULLET,obj.xPos, obj.yPos +15);
jjOBJ @ bull2 = jjObjects[bulletID2];
bull2.determineCurAnim(114,1 );
obj.age=0;
bull2.xAcc = 0;
bull2.xSpeed = 0;
bull2.yAcc = 0.15;
bull2.ySpeed = 0;
bull2.counterEnd = 80;
bull2.playerHandling = HANDLING::ENEMYBULLET;
bull2.killAnim=jjObjectPresets[OBJECT::RFBULLET].killAnim;
jjSample(obj.xPos, obj.yPos, SOUND::AMMO_LAZRAYS);
}
break;
}
case STATE::FIRE:
obj.counter++;
if(obj.counter==30)
{
obj.state=STATE::IDLE;
obj.determineCurAnim(ANIM::CUSTOM[26],0);
}
break;
case STATE::DEACTIVATE:
obj.deactivate();
return;
case STATE::KILL:
obj.delete();
return;
}
obj.draw();
}
}
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.