//Fake enemy
//Set to not be a beatable enemy
//Set to not return on death
//Will die along with main boss
//Must be placed on screen in enemy editor and set up like other enemies
ffc script Fake_Agahnim{
void run(int enemyid){
int i;
npc ghost = Ghost_InitAutoGhost(this, enemyid);
int SFX = ghost->Attributes[0];
int SPR = ghost->Attributes[1];
int combo = ghost->Attributes[10];
int attackCooldown = ghost->Haltrate*10;
float angle = Rand(360);
bool attackCond = false;
eweapon fireball;
int counter=-1;
int attack;
int X;
int Y;
Ghost_SetSize(this,ghost,2,2);
while(true){
if(Ghost_Dir==DIR_UP)
Ghost_Data = combo;
else if(Ghost_Dir==DIR_DOWN)
Ghost_Data = combo+1;
else if(Ghost_Dir==DIR_LEFT)
Ghost_Data = combo+2;
else if(Ghost_Dir==DIR_RIGHT)
Ghost_Data = combo+3;
if(attackCooldown>0){
counter = Ghost_ConstantWalk4(counter, ghost->Step, ghost->Rate, ghost->Homing, ghost->Hunger);
attackCooldown--;
}
else if(attackCooldown<=0)
attackCond=true;
if(attackCond){
Gen_Explode_Waitframes(this,ghost, Choose(32, 48, 96));
TeleportNPC(this, ghost);
angle = Angle(ghost->X+16,ghost->Y+16,CenterLinkX(),CenterLinkY());
if(Between(angle,0,45))
angle=0;
else if(Between(angle,46,135))
angle=90;
else if(Between(angle,136,225))
angle= 180;
else if(Between(angle,226,315))
angle= 270;
else
angle= 0;
if(angle==90){
Ghost_Dir=DIR_DOWN;
Ghost_Data = combo+1;
X= 12;
Y= 32;
}
else if(angle==180){
Ghost_Dir=DIR_LEFT;
Ghost_Data = combo+2;
X= -16;
Y= 12;
}
else if(angle==270){
Ghost_Dir=DIR_UP;
Ghost_Data = combo;
X= 12;
Y= -16;
}
else{
Ghost_Dir= DIR_RIGHT;
Ghost_Data = combo+3;
X= 32;
Y= 12;
}
Ghost_Waitframes(this,ghost,30);
fireball = FireEWeapon(EW_MAGIC,ghost->X+X,ghost->Y+Y,DegtoRad(angle), 200,
ghost->WeaponDamage, SPR, SFX,0);
attackCooldown = ghost->Haltrate*10;
attackCond = false;
}
Gen_Explode_Waitframe(this,ghost);
}
}
}
ffc script Agahnim{
void run(int enemyid){
int i;
npc ghost = Ghost_InitAutoGhost(this, enemyid);
int SFX = ghost->Attributes[0];
int SPR = ghost->Attributes[1];
int combo = ghost->Attributes[10];
int attackCooldown = ghost->Haltrate*10;
float angle = Rand(360);
bool attackCond = false;
eweapon fireball;
int counter=-1;
int attack;
int X;
int Y;
Ghost_SetSize(this,ghost,2,2);
while(true){
if(Ghost_Dir==DIR_UP)
Ghost_Data = combo;
else if(Ghost_Dir==DIR_DOWN)
Ghost_Data = combo+1;
else if(Ghost_Dir==DIR_LEFT)
Ghost_Data = combo+2;
else if(Ghost_Dir==DIR_RIGHT)
Ghost_Data = combo+3;
if(attackCooldown>0){
counter = Ghost_ConstantWalk4(counter, ghost->Step, ghost->Rate, ghost->Homing, ghost->Hunger);
attackCooldown--;
}
else if(attackCooldown<=0)
attackCond=true;
if(attackCond){
Gen_Leader_Waitframes(this,ghost, Choose(32, 48, 96));
if(Rand(0,100)>51)
attack= 1;
else
attack=0;
if(attack==0){
TeleportNPC(this, ghost);
angle = Angle(ghost->X+16,ghost->Y+16,CenterLinkX(),CenterLinkY());
if(Between(angle,0,45))
angle=0;
else if(Between(angle,46,135))
angle=90;
else if(Between(angle,136,225))
angle= 180;
else if(Between(angle,226,315))
angle= 270;
else
angle= 0;
if(angle==90){
Ghost_Dir=DIR_DOWN;
Ghost_Data = combo+1;
X= 12;
Y= 32;
}
else if(angle==180){
Ghost_Dir=DIR_LEFT;
Ghost_Data = combo+2;
X= -16;
Y= 12;
}
else if(angle==270){
Ghost_Dir=DIR_UP;
Ghost_Data = combo;
X= 12;
Y= -16;
}
else{
Ghost_Dir= DIR_RIGHT;
Ghost_Data = combo+3;
X= 32;
Y= 12;
}
Gen_Leader_Waitframes(this,ghost,30);
fireball = FireEWeapon(EW_MAGIC,ghost->X+X,ghost->Y+Y,DegtoRad(angle), 200,
ghost->WeaponDamage, SPR, SFX,0);
}
else{
X= 120;
Y= 32;
angle = Angle(CenterX(ghost), CenterY(ghost), X,Y);
Ghost_Data= combo+1;
Gen_Leader_Waitframe(this,ghost);
while(Ghost_CanMove(AngleDir8(angle), 16, 0)){
Ghost_MoveAtAngle(angle, 5, 0);
Phantom_Rush(this, ghost);
Gen_Leader_Waitframe(this,ghost);
}
Lightning(this,ghost);
}
attackCooldown = ghost->Haltrate*10;
attackCond = false;
}
Gen_Leader_Waitframe(this,ghost);
}
}
}
//Newbie boss functions by Moosh
const int GALE_WARP_SFX = 91;
void TeleportNPC(ffc this, npc ghost){
int w = ghost->TileWidth;
int h = ghost->TileHeight;
Game->PlaySound(GALE_WARP_SFX);
int tc;
ghost->CollDetection = false;
for(int i=0; i<16; i++){
if(i%2==0)
ghost->DrawYOffset = -1000;
else
ghost->DrawYOffset = -2;
Gen_Explode_Waitframe(this,ghost);
}
ghost->DrawYOffset = -1000;
tc = Rand(176);
for(int i=0; i<352&&(!CanPlaceNPC(ghost, ComboX(tc),
ComboY(tc))||Distance(ComboX(tc)+ghost->HitWidth/2,
ComboY(tc)+ghost->HitHeight/2, CenterLinkX(), CenterLinkY())<((w+h)/2)*8+32); i++){
if(i>=176)
tc = i-176;
else
tc = Rand(176);
}
Ghost_X = ComboX(tc);
Ghost_Y = ComboY(tc);
Gen_Explode_Waitframe(this,ghost);
Ghost_Dir = AngleDir4(Angle(CenterX(ghost), CenterY(ghost), CenterLinkX(), CenterLinkY()));
for(int i=0; i<16; i++){
if(i%2==0)
ghost->DrawYOffset = -1000;
else
ghost->DrawYOffset = -2;
Gen_Explode_Waitframe(this,ghost);
}
ghost->DrawYOffset = -2;
ghost->CollDetection = true;
}
bool CanPlaceNPC(npc ghost, int X, int Y){
for(int x=ghost->HitXOffset; x<=ghost->HitXOffset+ghost->HitWidth-1; x=Min(x+8, ghost->HitXOffset+ghost->HitWidth-1)){
for(int y=ghost->HitYOffset; y<=ghost->HitYOffset+ghost->HitHeight-1; y=Min(y+8, ghost->HitYOffset+ghost->HitHeight-1)){
if(!Ghost_CanMovePixel(X+x, Y+y))
return false;
if(y==ghost->HitYOffset+ghost->HitHeight-1)
break;
}
if(x==ghost->HitXOffset+ghost->HitWidth-1)
break;
}
return true;
}
void Phantom_Rush(ffc this, npc ghost){
int tile = Game->ComboTile(this->Data);
lweapon trail = CreateLWeaponAt(LW_SCRIPT5, ghost->X+ghost->DrawXOffset, ghost->Y+ghost->DrawYOffset);
trail->Extend = 3;
trail->TileWidth = ghost->TileWidth;
trail->TileHeight = ghost->TileHeight;
trail->CSet = this->CSet;
trail->Tile = tile;
trail->OriginalTile = tile;
trail->DrawStyle = DS_PHANTOM;
trail->DeadState = 8;
}
//Lightning functions by Dimi
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--;
}
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], 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 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 lineBoxCollisionlineBoxCollision
//Utility functions from lweapons.zh
//Uses to make a boss using the Gen_Explode_Waitframe wait for a certain number of frames before doing something.
void Gen_Explode_Waitframes(ffc this, npc ghost,int frames){
for(;frames>0;frames--){
Gen_Explode_Waitframe(this,ghost);
}
}
//A general utility function to make a boss explode on death.
void Gen_Explode_Waitframe(ffc this, npc ghost){
if(!Ghost_Waitframe(this, ghost, false, false)){
Ghost_DeathAnimation(this, ghost, 2);
Quit();
}
}
//Kills all npcs on screen when this enemy dies.
void Gen_Leader_Waitframe(ffc this, npc ghost){
if(!Ghost_Waitframe(this, ghost, false, false)){
Ghost_DeathAnimation(this, ghost, 2);
for(int i =Screen->NumNPCs();i>0;i--){
npc n = Screen->LoadNPC(i);
n->HP = 0;
}
Quit();
}
}
void Gen_Leader_Waitframes(ffc this, npc ghost, int frames){
for(;frames>0;frames--)
Gen_Leader_Waitframe(this,ghost);
}
//Test if one location is between two others.
//D0- Location to test
//D1- Lower bound
//D2- Higher bound
bool Between(int loc,int greaterthan, int lessthan){
if(loc>=greaterthan && loc<=lessthan)return true;
return false;
}