const int SFX_BLIND_BERSERK = 31;//Sound to play,when boss goes berserk
//Blind the Thief from Link to the Past
//Moves around, firing eweapons at Link. whehen damaged high rnough, spawns one loose head enemy, when all loose head enemies are spawned, he will move faster.
//Uses 2 rows of tiles, 1 for normal movement and for stunned state (4 frames.)
ffc script Blind_the_Thief{
void run(int enemyID){
npc ghost = Ghost_InitAutoGhost(this, enemyID);
int HF = ghost->Homing;
int HR = ghost->Haltrate;
int RR = ghost->Rate;
int HNG = ghost->Hunger;
int SPD = ghost->Step;
int WPND = ghost->WeaponDamage;
int sizex = Ghost_GetAttribute(ghost, 0, 4);//Tile Width
int sizey = Ghost_GetAttribute(ghost, 1, 2);//Tile Height
int looseheadID = Ghost_GetAttribute(ghost, 2, ghost->ID+1);//ID of loose heads enemy
int numheads = Ghost_GetAttribute(ghost, 3, 3);//Number of heads hidden inside
int berserkSPD = Ghost_GetAttribute(ghost, 4, 100);//Speed of enemy, when it went berserk
int shotspeed = Ghost_GetAttribute(ghost, 5, 120);//Delay between shooting, in frames.
int WPNS = Ghost_GetAttribute(ghost, 6, -1);//Eweapon sprite.
int knockdown = Ghost_GetAttribute(ghost, 7, 180);//Knockdown duration, un frames. Used when spawning head. If >300 cooldown can be fast-forwarded with explosions.
int xOffset = Ghost_GetAttribute(ghost, 8, 32);// X Offset used for head spawning and shooting.
int yOffset = Ghost_GetAttribute(ghost, 9, 0);// Y Offset used for head spawning and shooting.
ghost->Extend=3;
Ghost_SetSize(this, ghost, sizex, sizey);
if (sizex>2)Ghost_SetHitOffsets(ghost, 4, 4, 8, 8);
int State = 0;
int haltcounter = -1;
float angle=Rand(360);
int statecounter = 0;
eweapon e;
lweapon l;
int heads = 0;
int shootcounter=shotspeed;
int shoottimer =0;
int Ghost_MaxHP = Ghost_HP;
int hpthreshold = Lerp(0, Ghost_MaxHP,1-((heads+1)/(numheads+1)));
int origtile = ghost->OriginalTile;
int offset = 0;
int facedir = 0;
npc head = Screen->CreateNPC(looseheadID);
int headtile=head->OriginalTile;
Remove(head);
bool berserk=false;
Ghost_SetFlag(GHF_NORMAL);
Ghost_SetFlag(GHF_IGNORE_WATER);
Ghost_SetFlag(GHF_IGNORE_PITS);
Ghost_SetFlag(GHF_NO_FALL);
Ghost_SetFlag(GHF_8WAY);
Ghost_UnsetFlag(GHF_KNOCKBACK);
Ghost_SetFlag(GHF_FLYING_ENEMY);
Ghost_SpawnAnimationPuff(this, ghost);
while(true){
if (State==0){
haltcounter = Ghost_ConstantWalk8(haltcounter, SPD, RR, HF, HNG);
facedir = AngleDir4(Angle(ghost->X+xOffset, ghost->Y+yOffset, Link->X, Link->Y));
if (!berserk)Screen->FastTile (3,ghost->X+xOffset, ghost->Y+yOffset, headtile+facedir, Ghost_CSet,OP_OPAQUE);
shootcounter--;
if (shootcounter<=0){
e = FireAimedEWeapon(ghost->Weapon, ghost->X+xOffset, ghost->Y+yOffset, 0, 180, WPND, WPNS, -1, 0);
shootcounter=shotspeed;
}
if (Ghost_HP>0 && Ghost_HP<=hpthreshold){
head = CreateNPCAt(looseheadID, Ghost_X+xOffset, Ghost_Y+yOffset);
ghost->CollDetection =false;
ghost->OriginalTile = GH_BLANK_TILE;
heads++;
hpthreshold = Lerp(0, Ghost_MaxHP,1-((heads+1)/(numheads+1)));
if (heads>=numheads){
SPD = berserkSPD;
berserk=true;
}
statecounter=knockdown;
State=1;
}
}
else if (State==1){
for (int i=0;i<=3;i++){
if (i==4){
offset = 3*Ghost_TileWidth+20*Ghost_TileHeight;
break;
}
if (statecounter<=(ghost->ASpeed*i)||(knockdown-statecounter)<(ghost->ASpeed*i)){
offset = i*Ghost_TileWidth+20*Ghost_TileHeight;
break;
}
}
Screen->DrawTile (2, ghost->X, ghost->Y,origtile+offset, Ghost_TileWidth, Ghost_TileHeight,Ghost_CSet, -1, -1,0, 0, 0,0,true, OP_OPAQUE);
if (statecounter>=300){
for (int i=1;i<=Screen->NumLWeapons();i++){
l = Screen->LoadLWeapon(i);
if (l->ID!=LW_BOMBBLAST && l->ID!=LW_SBOMBBLAST) continue;
if (!Collision(l,ghost))continue;
statecounter = ghost->ASpeed*3;
break;
}
}
statecounter--;
if (statecounter<=0){
ghost->CollDetection=true;
ghost->OriginalTile=origtile;
State=0;
if (heads==numheads)Game->PlaySound(SFX_BLIND_BERSERK);
}
}
// debugValue(1, hpthreshold);
// debugValue(2, heads);
if(!Ghost_Waitframe(this, ghost, false, false)){
for (int i=1;i<=Screen->NumNPCs();i++){
npc n=Screen->LoadNPC(i);
if (n->ID!=looseheadID) continue;
SetEnemyProperty(n, ENPROP_HP, 0);
}
Ghost_DeathAnimation(this, ghost, 2);
Quit();
}
}
}
}
ffc script BlindLooseHead{
void run(int enemyID){
npc ghost = Ghost_InitAutoGhost(this, enemyID);
int HF = ghost->Homing;
int HR = ghost->Haltrate;
int RR = ghost->Rate;
int HNG = ghost->Hunger;
int SPD = ghost->Step;
int WPND = ghost->WeaponDamage;
int firenum = Ghost_GetAttribute(ghost, 0, 1);//Number of eweapons to fire per burst
int shotspeed = Ghost_GetAttribute(ghost, 1, 60);//Delay between shots, in frames. Enemy won`t fire , if Weapon Damage is 0.
int ewsprite = Ghost_GetAttribute(ghost, 2, -1);//Eweapon sprite
int firerate = Ghost_GetAttribute(ghost, 3, 4);
Ghost_SetFlag(GHF_NORMAL);
Ghost_SetFlag(GHF_IGNORE_WATER);
Ghost_SetFlag(GHF_IGNORE_PITS);
Ghost_SetFlag(GHF_NO_FALL);
Ghost_SetFlag(GHF_8WAY);
Ghost_UnsetFlag(GHF_KNOCKBACK);
Ghost_SetFlag(GHF_FLYING_ENEMY);
int State = 0;
int shotcounter=shotspeed;
int shoottimer =0;
int haltcounter = -1;
eweapon e;
int defs[18];
Ghost_StoreDefenses(ghost,defs);
while(true){
if (State==0){
haltcounter = Ghost_ConstantWalk8(haltcounter, SPD, RR, HF, HNG);
shotcounter--;
if (shotcounter==0 && WPND>0){
shoottimer = firerate*firenum;
shotcounter=shotspeed;
}
if (shoottimer>0){
if ((shoottimer%firerate)==0){
e = FireAimedEWeapon(ghost->Weapon, Ghost_X, Ghost_Y, 0, 200, WPND, ewsprite, -1, 0);
}
shoottimer--;
}
}
if (!Ghost_Waitframe(this, ghost, false, false)){
Quit();
}
}
}
}