Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
![]() |
Holiday Hare 24![]() |
PurpleJazz | Single player | 10 | ![]() |
#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_HH24 {
int golemDeathCount = 0;
int golemDuoHP = 0;
const float PI = 3.1415927f;
int maxHP = 0;
void ICEGOLEMEDIT(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].bulletHandling=HANDLING::DETECTBULLET;
jjObjectPresets[eventID].behavior = SMOKE_HH24::IceGolemEdit();
jjObjectPresets[eventID].determineCurAnim(ANIM::CUSTOM[17], 0);
jjObjectPresets[eventID].counter = 0;
jjObjectPresets[eventID].energy = jjObjectPresets[eventID].var[0] = maxHP = jjObjectPresets[eventID].var[4] = hp;
jjObjectPresets[eventID].xSpeed = 1 + (jjDifficulty/2);
jjObjectPresets[eventID].var[2] = 140;
jjObjectPresets[eventID].deactivates = false;
}
class IceGolemEdit : jjBEHAVIORINTERFACE {
int armor, armorCounter;
float bossHP = GolemMaxHP;
void onBehave(jjOBJ @ obj) {
int playerID = obj.findNearestPlayer(10000000);
float x = -obj.xPos + jjPlayers[playerID].xPos;
float y = -obj.yPos + jjPlayers[playerID].yPos;
if(obj.state==STATE::START)
{
golemDuoHP = obj.energy * 2;
bossHP = GolemMaxHP;
}
if (golemDeathCount < 0) {
obj.delete();
}
if (obj.var[4] > obj.energy) {
golemDuoHP -= (obj.var[4] - obj.energy);
obj.var[4] = obj.energy;
}
obj.energy = int(bossHP);
if (obj.justHit != 0) armorCounter = 0;
else armorCounter++;
if (armorCounter > 0) {
if (armorCounter < 35) {
if (armorCounter % 7 == 0) {
armor--;
}
}
if (armorCounter >= 70) {
if (armorCounter % 4 == 0) {
armor--;
}
}
}
if (armor > 20) armor = 20;
if (armor < 0) armor = 0;
if (golemDeathCount > 0 && obj.counter < 140) {
if (obj.var[1] == 0) {
obj.bulletHandling = HANDLING::DETECTBULLET;
obj.counter = 45;
obj.special = 0;
obj.var[1] = 1;
obj.xSpeed = (2+jjDifficulty) * obj.direction;
jjAlert("||YOU WILL PAY FOR THAT!",false,STRING::MEDIUM);
obj.var[5] = 1;
if (obj.energy < obj.var[0] - 4) {
bossHP += maxHP;
obj.energy += maxHP;
obj.var[4] = obj.energy;
golemDuoHP = int(bossHP);
} else {
obj.energy = golemDuoHP = obj.var[0];
obj.var[4] = obj.energy;
}
jjSamplePriority(SOUND::INTRO_MONSTER);
jjSamplePriority(SOUND::INTRO_MONSTER);
}
}
//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)
{
golemDeathCount++;
obj.delete();
}
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.var[1] == 0) {
if (obj.freeze == 0 && obj.special == (52-(jjDifficulty*8))) // 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_HH24::SpikeBall;
bull2.counterEnd=87;
// bull2.xSpeed = obj.direction * 4;
bull2.xSpeed=obj.direction*2.5;
bull2.ySpeed=-4;
bull2.yAcc=0.1;
bull2.xAcc=0;
// bull2.yAcc=-0.1;
bull2.playerHandling = HANDLING::ENEMYBULLET;
jjSamplePriority(SOUND::AMMO_ICEGUNPU);
}
} else {
if (obj.freeze == 0 && obj.special >= 14 && obj.special % (11-(jjDifficulty*2)) == 0 && obj.special <= 49) // shoot bullets
{
int bulletID3 = jjAddObject(OBJECT::BLASTERBULLET, obj.xPos + (42 * obj.direction), obj.yPos - 40, obj.objectID, CREATOR::OBJECT);
jjOBJ @ o = jjObjects[bulletID3];
o.behavior = Icicle;
o.determineCurAnim(ANIM::CUSTOM[17], 3);
o.direction = o.xSpeed < 0? 1:-1;
o.xSpeed = -5 * o.direction;
o.ySpeed = -1.5 + (0.1*(jjRandom()%30));
o.xAcc = 0;
o.yAcc = 0;
o.counterEnd = 90;
o.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
o.playerHandling = HANDLING::ENEMYBULLET;
jjSamplePriority(SOUND::AMMO_ICEGUNPU);
}
}
if (obj.special == 57) //end attack phase; start walking phase
{
obj.special = 0;
obj.counter = obj.var[1] == 0? 0 : (50+(jjDifficulty*15));
obj.xSpeed = (obj.var[1] == 0? 1.5:(2+jjDifficulty)) * (jjRandom()% 2 > 0? 1:-1);
obj.determineCurAnim(ANIM::CUSTOM[17], 0); //walking animation
}
}
if ((obj.special == 0) && (x * x + y * y <= 560 * 560)) // 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, obj.var[1] > 0? SPRITE::TINTED : SPRITE::NORMAL, 50);
} else
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::SINGLECOLOR, jjLocalPlayers[0].blink == 0? 15:32);
}
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;
float multiplier = ((bullet.var[3] == 4 || bullet.var[3] == 5)? 0.4f : 0.6f) * (player.blink == 0? 1:0.5);
bossHP -= ((damageCalc(obj, bullet, armor, player) > (bullet.animSpeed * multiplier))? damageCalc(obj, bullet, armor, player) : (bullet.animSpeed * multiplier)) * (player.blink == 0? 1:0.5);
armor += bullet.animSpeed;
/*jjPARTICLE@ text = jjAddParticle(PARTICLE::STRING);
if (text !is null) {
text.xPos = obj.xPos;
text.yPos = obj.yPos;
text.ySpeed = -0.25;
text.string.text = "" + (damageCalc(obj,bullet,armor) > (bullet.animSpeed * multiplier)? damageCalc(obj,bullet,armor) : (bullet.animSpeed * multiplier));
}*/
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;
if (golemDeathCount == 0 || obj.var[5] == 1) 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;
}
}
float damageCalc(jjOBJ@ obj, jjOBJ@ bullet, int armor, jjPLAYER@ play) {
if (armor <= bullet.animSpeed) {
return bullet.animSpeed * (play.blink == 0? 1:0.125);
} else {
return (bullet.animSpeed - ((0.0125f * (bullet.animSpeed*3)) * armor)) * (play.blink == 0? 1:0.125);
}
}
void SpikeBall(jjOBJ @ obj) {
obj.behave(BEHAVIOR::BULLET, true);
if (obj.state == STATE::EXPLODE && obj.isActive) {
obj.unfreeze(1);
if (jjDifficulty > 0) {
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 = 4*sin(i*3.141592/4);
o.yAcc=0;
o.xAcc=0;
o.xSpeed = 4*cos(i*3.141592/4);
o.counterEnd = 45;
o.killAnim = jjObjectPresets[OBJECT::ICEBULLET].killAnim;
o.playerHandling = HANDLING::ENEMYBULLET;
}
}
obj.delete();
}
}
void Icicle(jjOBJ @ obj) {
if (obj.state == STATE::EXPLODE && obj.isActive) {
obj.unfreeze(1);
obj.delete();
}
obj.behave(BEHAVIOR::BULLET, true);
}
}
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.