const int VITREOUS_EYE = 209;//Enemy Id for small eyes.
ffc script Vitreous{
void run(int enemyID){
npc n = Ghost_InitAutoGhost(this, enemyID);
Ghost_SetSize(this,n,2,3);
int combo = n->Attributes[10];
Ghost_Data = combo;
//Remember speed so we can change it.
float speed = n->Step/100;
int step = 0;
//Handles boss behavior.
int mode = 1;
//Make it wait before trying to attack you.
int mode_timer;
//Create small eyes.
npc n2 = Screen->CreateNPC(VITREOUS_EYE);
npc n3 = Screen->CreateNPC(VITREOUS_EYE);
npc n4 = Screen->CreateNPC(VITREOUS_EYE);
npc n5 = Screen->CreateNPC(VITREOUS_EYE);
//Position boss.
Ghost_X = 112;
Ghost_Y = 32;
//Position eyes.
n2->X = Ghost_X-16;
n2->Y = Ghost_Y+32;
n3->X = Ghost_X;
n3->Y = Ghost_Y+48;
n4->X = Ghost_X+16;
n4->Y = Ghost_Y+48;
n5->X = Ghost_X+32;
n5->Y = Ghost_Y+32;
//Activates if it is time to change behavior.
int turncombo = combo+1;
Ghost_SetHitOffsets(n,6,11,0,0);
//Determine how often to fire lightning.
int fire_timer= Rand(100,200);
Ghost_CSet= 5;
Ghost_SetFlag(GHF_FAKE_Z);
Ghost_SetFlag(GHF_KNOCKBACK_4WAY);
this->Flags[FFCF_OVERLAY]= true;
int eye_pick;
bool Jump_Eye;
n2->Defense[NPCD_SWORD]= NPCDT_IGNORE;
n3->Defense[NPCD_SWORD]= NPCDT_IGNORE;
n4->Defense[NPCD_SWORD]= NPCDT_IGNORE;
n5->Defense[NPCD_SWORD]= NPCDT_IGNORE;
while(n->HP > 0){
if(mode==1 && fire_timer<=0){
n2->Defense[NPCD_SWORD]= NPCDT_IGNORE;
n3->Defense[NPCD_SWORD]= NPCDT_IGNORE;
n4->Defense[NPCD_SWORD]= NPCDT_IGNORE;
n5->Defense[NPCD_SWORD]= NPCDT_IGNORE;
Lightning(this,n);
if(!Jump_Eye){
if(n2->isValid()
&& n3->isValid()
&& n4->isValid()
&& n5->isValid())
eye_pick= Choose(1,2,3,4);
else if(!n2->isValid()
&& n3->isValid()
&& n4->isValid()
&& n5->isValid())
eye_pick= Choose(2,3,4);
else if(!n2->isValid()
&& !n3->isValid()
&& n4->isValid()
&& n5->isValid())
eye_pick= Choose(3,4);
else if(!n2->isValid()
&& !n3->isValid()
&& !n4->isValid()
&& n5->isValid())
eye_pick= 4;
else if(n2->isValid()
&& !n3->isValid()
&& n4->isValid()
&& n5->isValid())
eye_pick= Choose(1,3,4);
else if(n2->isValid()
&& !n3->isValid()
&& !n4->isValid()
&& n5->isValid())
eye_pick= Choose(1,4);
else if(n2->isValid()
&& !n3->isValid()
&& !n4->isValid()
&& !n5->isValid())
eye_pick= 1;
else if(!n2->isValid()
&& n3->isValid()
&& !n4->isValid()
&& n5->isValid())
eye_pick= Choose(2,4);
else if(!n2->isValid()
&& n3->isValid()
&& !n4->isValid()
&& !n5->isValid())
eye_pick= 2;
else if(n2->isValid()
&& !n3->isValid()
&& n4->isValid()
&& !n5->isValid())
eye_pick= Choose(1,3);
else if(!n2->isValid()
&& !n3->isValid()
&& n4->isValid()
&& !n5->isValid())
eye_pick= 3;
else if(n2->isValid()
&& n3->isValid()
&& n4->isValid()
&& !n5->isValid())
eye_pick= Choose(1,2,3);
else if(n2->isValid()
&& n3->isValid()
&& !n4->isValid()
&& n5->isValid())
eye_pick= Choose(1,2,4);
else if(n2->isValid()
&& n3->isValid()
&& !n4->isValid()
&& !n5->isValid())
eye_pick= Choose(1,2);
else if(!n2->isValid()
&& n3->isValid()
&& n4->isValid()
&& !n5->isValid())
eye_pick= Choose(2,3);
Jump_Eye = true;
fire_timer= Rand(100,200);
}
else{
if(n2->isValid()){
n2->Defense[NPCD_SWORD]= NPCDT_IGNORE;
while(n2->X-(n->X-16)>4 && n2->Y-(n->Y+32)>4){
MoveToXY(n2,n->X-16,n->Y+32);
Gen_Explode_Waitframe(this,n);
}
n2->X= n->X-16;
n2->Y= n->Y+32;
}
if(n3->isValid()){
n3->Defense[NPCD_SWORD]= NPCDT_IGNORE;
while(n3->X-n->X>4 && n3->Y-(n->Y+48)>4){
MoveToXY(n3,n->X,n->Y+48);
Gen_Explode_Waitframe(this,n);
}
n3->X= n->X;
n3->Y= n->Y+48;
}
if(n4->isValid()){
n4->Defense[NPCD_SWORD]= NPCDT_IGNORE;
while(n4->X-(n->X+16)>4 && n4->Y-(n->Y+48)>4){
MoveToXY(n4,n->X+16,n->Y+48);
Gen_Explode_Waitframe(this,n);
}
n4->X = n->X+16;
n4->Y= n->Y+48;
}
if(n5->isValid()){
n5->Defense[NPCD_SWORD]= NPCDT_IGNORE;
while(n5->X-(n->X+32)>4 && n5->Y-(n->Y+32)>4){
MoveToXY(n5,n->X+32,n->Y+32);
Gen_Explode_Waitframe(this,n);
}
n5->X= n->X+32;
n5->Y= n->Y+32;
}
Jump_Eye = false;
}
fire_timer= Rand(100,200);
}
else if(mode==1 && Jump_Eye){
if(eye_pick==1){
n2->Defense[NPCD_SWORD]=NPCDT_NONE;
MoveToLink(n2);
}
else if(eye_pick==2){
n3->Defense[NPCD_SWORD]=NPCDT_NONE;
MoveToLink(n3);
}
else if(eye_pick==3){
n4->Defense[NPCD_SWORD]=NPCDT_NONE;
MoveToLink(n4);
}
else if(eye_pick==4){
n5->Defense[NPCD_SWORD]=NPCDT_NONE;
MoveToLink(n5);
}
}
//Time to bounce towards Link
else if(mode == 2 && mode_timer<=0){
Ghost_SetAllDefenses(n, NPCDT_NONE);
//Set speed.
step = speed;
//Change appearance
if(Ghost_Data!=turncombo)
Ghost_Data=turncombo;
//Jump if not jumping
if(Ghost_Jump==0)
Ghost_Jump = 3;
//In the air.
while(Ghost_Jump>0){
//Move towards Link
if(Ghost_X>Link->X)Ghost_X-=step;
else if(Ghost_X<Link->X)Ghost_X+=step;
if(Ghost_Y>Link->Y)Ghost_Y-=step;
else if(Ghost_Y<Link->Y)Ghost_Y+=step;
Gen_Explode_Waitframe(this,n);
}
}
//Handles changing modees.
//All eyes are dead.
if(n2->HP <=0
&& n3->HP <= 0
&& n4->HP <= 0
&& n5->HP <= 0
&& mode == 1){
mode = 2;
mode_timer = 90;
}
if(mode_timer>0)mode_timer--;
else mode_timer =0;
fire_timer--;
Gen_Explode_Waitframe(this,n);
}
}
}
const int SFX_BOLT = 66;
void Lightning(ffc this, npc ghost){
int Lightning1X[25];
int Lightning1Y[25];
int Lightning2X[25];
int Lightning2Y[25];
int Lightning3X[25];
int Lightning3Y[25];
int Lightning4X[25];
int Lightning4Y[25];
int HitCounter = 0;
int i;
int m= Rand(2,6);
for (; m!= 0;){
if (m > 0) m--;
for (i = 24; i >= 0; i--){
Lightning1X[i] = this->X+16;
Lightning1Y[i] = this->Y+32;
Lightning2X[i] = this->X+16;
Lightning2Y[i] = this->Y+32;
Lightning3X[i] = this->X+16;
Lightning3Y[i] = this->Y+32;
Lightning4X[i] = this->X+16;
Lightning4Y[i] = this->Y+32;
}
Game->PlaySound(SFX_BOLT);
while((Lightning1Y[24] < 176
|| Lightning2Y[24] < 176
|| Lightning3Y[24] < 176
|| Lightning4Y[24] < 176)){
bool Struck = false;
for (int l = 0; l <= 2; l++){
int Angle1 = Choose(210, 150, 225, 135);
Angle1 -= 90;
if(Link->X<=ghost->X-16)
Angle1+=22;
else if(Link->X>=ghost->X+48)
Angle1-=22;
ShiftArray(Lightning1X);
ShiftArray(Lightning1Y);
Lightning1X[0] += VectorX(10, Angle1);
Lightning1Y[0] += VectorY(10, Angle1);
int Angle2 = Choose(210, 150, 225, 135);
Angle2 -= 90;
if(Link->X<=ghost->X-16)
Angle2+=22;
else if(Link->X>=ghost->X+48)
Angle2-=22;
ShiftArray(Lightning2X);
ShiftArray(Lightning2Y);
Lightning2X[0] += VectorX(10, Angle2);
Lightning2Y[0] += VectorY(10, Angle2);
int Angle3 = Choose(210, 150, 225, 135);
Angle3 -= 90;
if(Link->X<=ghost->X-16)
Angle3+=22;
else if(Link->X>=ghost->X+48)
Angle3-=22;
ShiftArray(Lightning3X);
ShiftArray(Lightning3Y);
Lightning3X[0] += VectorX(10, Angle3);
Lightning3Y[0] += VectorY(10, Angle3);
int Angle4 = Choose(210, 150, 225, 135);
Angle4 -= 90;
if(Link->X<=ghost->X-16)
Angle4+=22;
else if(Link->X>=ghost->X+48)
Angle4-=22;
ShiftArray(Lightning4X);
ShiftArray(Lightning4Y);
Lightning4X[0] += VectorX(10, Angle4);
Lightning4Y[0] += VectorY(10, Angle4);
for (i = 24; i > 0; i--){
Screen->Line(2, Lightning1X[i], Lightning1Y[i], Lightning1X[i-1], Lightning1Y[i-1], 0x0B, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning2X[i], Lightning2Y[i], Lightning2X[i-1], Lightning2Y[i-1], 0x0B, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning3X[i], Lightning3Y[i], Lightning3X[i-1], Lightning3Y[i-1], 0x0B, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning4X[i], Lightning4Y[i], Lightning4X[i-1], Lightning4Y[i-1], 0x0B, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning1X[i] - 1, Lightning1Y[i], Lightning1X[i-1] - 1, Lightning1Y[i-1], 0x0B, 2, 0, 0, 0, 64);
Screen->Line(2, Lightning2X[i] - 1, Lightning2Y[i], Lightning2X[i-1] - 1, Lightning2Y[i-1], 0x0B, 2, 0, 0, 0, 64);
Screen->Line(2, Lightning3X[i] - 1, Lightning3Y[i], Lightning3X[i-1] - 1, Lightning3Y[i-1], 0x0B, 2, 0, 0, 0, 64);
Screen->Line(2, Lightning4X[i] - 1, Lightning4Y[i], Lightning4X[i-1] - 1, Lightning4Y[i-1], 0x0B, 2, 0, 0, 0, 64);
if (!Struck){
if (lineBoxCollision(Lightning1X[i], Lightning1Y[i], Lightning1X[i-1], Lightning1Y[i-1], Link->X, Link->Y, Link->X+Link->HitWidth, Link->Y+Link->HitHeight, 0))
{
Struck = true;
if (HitCounter <= 0) HitCounter = 10;
continue;
}
if (lineBoxCollision(Lightning2X[i], Lightning2Y[i], Lightning2X[i-1], Lightning2Y[i-1], Link->X, Link->Y, Link->X+Link->HitWidth, Link->Y+Link->HitHeight, 0))
{
Struck = true;
if (HitCounter <= 0) HitCounter = 10;
continue;
}
if (lineBoxCollision(Lightning3X[i], Lightning3Y[i], Lightning3X[i-1], Lightning3Y[i-1], Link->X, Link->Y, Link->X+Link->HitWidth, Link->Y+Link->HitHeight, 0))
{
Struck = true;
if (HitCounter <= 0) HitCounter = 10;
continue;
}
if (lineBoxCollision(Lightning4X[i], Lightning4Y[i], Lightning4X[i-1], Lightning4Y[i-1], Link->X, Link->Y, Link->X+Link->HitWidth, Link->Y+Link->HitHeight, 0))
{
Struck = true;
if (HitCounter <= 0) HitCounter = 10;
continue;
}
}
}
}
if (Struck){
eweapon e = FireEWeapon(EW_SCRIPT10, Link->X+InFrontX(Link->Dir, 10), Link->Y+InFrontY(Link->Dir, 10), 0, 0, 8, -1, -1, EWF_UNBLOCKABLE);
SetEWeaponLifespan(e, EWL_TIMER, 1);
SetEWeaponDeathEffect(e, EWD_VANISH, 0);
e->DrawYOffset = -1000;
}
if (HitCounter > 0){
if (Link->HP > 0)
Screen->Rectangle(6, 0, 0, 256, 176, 1, 1, 0, 0, 0, true, OP_TRANS);
}
Gen_Explode_Waitframe(this,ghost);
for (i = 24; i > 0; i--){
Screen->Line(2, Lightning1X[i], Lightning1Y[i], Lightning1X[i-1], Lightning1Y[i-1], 0x0B, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning2X[i], Lightning2Y[i], Lightning2X[i-1], Lightning2Y[i-1], 0x0B, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning3X[i], Lightning3Y[i], Lightning3X[i-1], Lightning3Y[i-1], 0x0B, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning4X[i], Lightning4Y[i], Lightning4X[i-1], Lightning4Y[i-1], 0x0B, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning1X[i] - 1, Lightning1Y[i], Lightning1X[i-1] - 1, Lightning1Y[i-1], 0x01, 2, 0, 0, 0, 64);
Screen->Line(2, Lightning2X[i] - 1, Lightning2Y[i], Lightning2X[i-1] - 1, Lightning2Y[i-1], 0x01, 2, 0, 0, 0, 64);
Screen->Line(2, Lightning3X[i] - 1, Lightning3Y[i], Lightning3X[i-1] - 1, Lightning3Y[i-1], 0x01, 2, 0, 0, 0, 64);
Screen->Line(2, Lightning4X[i] - 1, Lightning4Y[i], Lightning4X[i-1] - 1, Lightning4Y[i-1], 0x01, 2, 0, 0, 0, 64);
}
if (HitCounter > 0){
if (Link->HP > 0)
Screen->Rectangle(6, 0, 0, 256, 176, 1, 1, 0, 0, 0, true, OP_OPAQUE);
HitCounter--;
}
Waitframe();
for (i = 24; i > 0; i--){
Screen->Line(2, Lightning1X[i], Lightning1Y[i], Lightning1X[i-1], Lightning1Y[i-1], 0x01, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning2X[i], Lightning2Y[i], Lightning2X[i-1], Lightning2Y[i-1], 0x01, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning3X[i], Lightning3Y[i], Lightning3X[i-1], Lightning3Y[i-1], 0x01, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning4X[i], Lightning4Y[i], Lightning4X[i-1], Lightning4Y[i-1], 0x01, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning1X[i] - 1, Lightning1Y[i], Lightning1X[i-1] - 1, Lightning1Y[i-1], 0x0B, 2, 0, 0, 0, 64);
Screen->Line(2, Lightning2X[i] - 1, Lightning2Y[i], Lightning2X[i-1] - 1, Lightning2Y[i-1], 0x0B, 2, 0, 0, 0, 64);
Screen->Line(2, Lightning3X[i] - 1, Lightning3Y[i], Lightning3X[i-1] - 1, Lightning3Y[i-1], 0x0B, 2, 0, 0, 0, 64);
Screen->Line(2, Lightning4X[i] - 1, Lightning4Y[i], Lightning4X[i-1] - 1, Lightning4Y[i-1], 0x0B, 2, 0, 0, 0, 64);
}
Gen_Explode_Waitframe(this,ghost);
for (i = 24; i > 0; i--){
Screen->Line(2, Lightning1X[i], Lightning1Y[i], Lightning1X[i-1], Lightning1Y[i-1], 0x01, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning2X[i], Lightning2Y[i], Lightning2X[i-1], Lightning2Y[i-1], 0x01, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning3X[i], Lightning3Y[i], Lightning3X[i-1], Lightning3Y[i-1], 0x01, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning4X[i], Lightning4Y[i], Lightning4X[i-1], Lightning4Y[i-1], 0x01, 1, 0, 0, 0, 128);
Screen->Line(2, Lightning1X[i] - 1, Lightning1Y[i], Lightning1X[i-1] - 1, Lightning1Y[i-1], 0x01, 2, 0, 0, 0, 64);
Screen->Line(2, Lightning2X[i] - 1, Lightning2Y[i], Lightning2X[i-1] - 1, Lightning2Y[i-1], 0x01, 2, 0, 0, 0, 64);
Screen->Line(2, Lightning3X[i] - 1, Lightning3Y[i], Lightning3X[i-1] - 1, Lightning3Y[i-1], 0x01, 2, 0, 0, 0, 64);
Screen->Line(2, Lightning4X[i] - 1, Lightning4Y[i], Lightning4X[i-1] - 1, Lightning4Y[i-1], 0x01, 2, 0, 0, 0, 64);
}
Gen_Explode_Waitframe(this,ghost);
}
}
while(HitCounter > 0){
if (Link->HP > 0)
Screen->Rectangle(6, 0, 0, 256, 176, 1, 1, 0, 0, 0, true, OP_OPAQUE);
Gen_Explode_Waitframe(this,ghost);
if (Link->HP > 0)
Screen->Rectangle(6, 0, 0, 256, 176, 1, 1, 0, 0, 0, true, OP_OPAQUE);
HitCounter--;
Gen_Explode_Waitframes(this,ghost,3);
}
}
void Gen_Explode_Waitframe(ffc this, npc ghost){
if(!Ghost_Waitframe(this, ghost, false, false)){
Ghost_DeathAnimation(this, ghost, 2);
Quit();
}
}
void Gen_Explode_Waitframes(ffc this, npc ghost,int frames){
for(;frames>0;frames--)
Gen_Explode_Waitframe(this,ghost);
}
const int NPC_INDEX_DELAY = 0;
void MoveToLink(npc ghost){
if(ghost->Misc[NPC_INDEX_DELAY]==0){
ghost->Misc[NPC_INDEX_DELAY]=3;
if(ghost->X<Link->X)ghost->X+=(ghost->Step/100);
else if(ghost->X>Link->X)ghost->X-=(ghost->Step/100);
if(ghost->Y<Link->Y)ghost->Y+=(ghost->Step/100);
else if(ghost->Y>Link->Y)ghost->Y-=(ghost->Step/100);
}
else if(ghost->Misc[NPC_INDEX_DELAY]>0)
ghost->Misc[NPC_INDEX_DELAY]--;
}
void MoveToXY(npc ghost,int X, int Y){
if(ghost->Misc[NPC_INDEX_DELAY]==0){
ghost->Misc[NPC_INDEX_DELAY]=3;
if(ghost->X<X)ghost->X++;
else if(ghost->X>X)ghost->X--;
if(ghost->Y<Y)ghost->Y++;
else if(ghost->Y>Y)ghost->Y--;
}
else if(ghost->Misc[NPC_INDEX_DELAY]>0)
ghost->Misc[NPC_INDEX_DELAY]--;
}
void ShiftArray(int Array){
for (int i = SizeOfArray(Array)-1; i > 0; i--)
Array[i] = Array[i-1];
}
// Function to see if a box has collided with a line
bool lineBoxCollision(int lineX1, int lineY1, int lineX2, int lineY2, int boxX1, int boxY1, int boxX2, int boxY2, int boxBorder)
{
// Shrink down the box for the border
boxX1 += boxBorder; boxY1 += boxBorder;
boxX2 -= boxBorder; boxY2 -= boxBorder;
// If the line isn't vertical
if(lineX2!=lineX1)
{
float i0 = (boxX1 - lineX1)/(lineX2-lineX1);
float i1 = (boxX2 - lineX1)/(lineX2-lineX1);
float yA = lineY1 + i0*(lineY2-lineY1);
float yB = lineY1 + i1*(lineY2-lineY1);
if(Max(boxX1, boxX2) >= Min(lineX1, lineX2) && Min(boxX1, boxX2) <= Max(lineX1, lineX2) &&
Max(boxY1, boxY2) >= Min(lineY1, lineY2) && Min(boxY1, boxY2) <= Max(lineY1, lineY2))
{
if(Min(boxY1, boxY2) > Max(yA, yB) || Max(boxY1, boxY2) < Min(yA, yB))
return false;
else
return true;
}
else
return false;
}
// If the line is vertical
else if(lineX1 >= boxX1 && lineX1 <= boxX2)
{
// Basically we need to find the top and bottom y values of the line to check for intersection
float lineYMin = lineY1;
float lineYMax = lineY2;
if(lineYMin > lineYMax)
{
lineYMin = lineY2;
lineYMax = lineY1;
}
// If either point intersects
if((boxY1 >= lineYMin && boxY1 <= lineYMax) || (boxY2 >= lineYMin && boxY2 <= lineYMax))
return true;
}
return false;
} //! End of lineBoxCollision