const int DRACULA2_ALT_FIRE_ASPEED = 4;//delay between Moving and shooting, in frames. Enemy won`t fire bombs, if Weapon Damage is 0.
const int CSET_DRACULA2_WARNING = 11;//CSet to render boss, when he is about to shhoot stuff at Link.
//const int CMB_DRACULA2_BODY = 1044;//Combo used to render alien body (5*5 tiles);
const int SPR_DRACULA2_FIREBALL = -1;//Sprite used for fireballs.
const int DRACULA2_BERSERK = 4;//HP threshold for boss going berserk(2x speed). 0 to disable.
//CV2 Illusionist boss
//Moves like Rotodisk, creates intangible rotating illusuions, ocassionally stops to fire stuff at Link. If it goes bersderk (low HP), it increases rotation speed
ffc script CV2Dracula{
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 origrange = Ghost_GetAttribute(ghost, 0, 60);//Rotation radius.
int speed = Ghost_GetAttribute(ghost, 1, 0);//Rotation speed, in degrees per frame. if set to 0, speed rendomizes after every fireball shot.
int initangle = Ghost_GetAttribute(ghost, 2, Rand(359));//Starting angle. 0 - random
int sizex = Ghost_GetAttribute(ghost, 3, 1);//Tile Width
int sizey = Ghost_GetAttribute(ghost, 4, 1);//Tile Height
int shotspeed = Ghost_GetAttribute(ghost, 5, 60);//delay between shooting fireballs
int NumIllusions = Ghost_GetAttribute(ghost, 6, 4);//Number of illusions to create while moving.
ghost->Extend=3;
Ghost_SetSize(this, ghost, sizex, sizey);
if (sizex>2 || sizey>2)Ghost_SetHitOffsets(ghost, 8, 8, 8, 8);
Ghost_SetFlag(GHF_IGNORE_ALL_TERRAIN);
Ghost_SetFlag(GHF_NO_FALL);
Ghost_SetFlag(GHF_MOVE_OFFSCREEN);
int range=0;
int origtile = ghost->OriginalTile;
int origcset = ghost->CSet;
int haltcounter = -1;
int origx = ghost->X;
int origy = ghost->Y;
int anglex = initangle;
Ghost_X = origx + range*Cos(anglex);
Ghost_Y = origy + range*Sin(anglex);
int shotcounter=shotspeed;
int defs[18];
Ghost_StoreDefenses(ghost,defs);
// if (ThunderbirdShieldBreach>0)Ghost_SetAllDefenses(ghost, NPCDT_IGNORE);
// int open = 0;
int state = 0;
// ghost->DrawXOffset=180;
int aimx = 0;
int aimy = 0;
int angle = initangle;
if (initangle >=360) angle =Rand(359);
int berserk=0;
if (speed==0)speed = (Rand(4)-2) * Cond (berserk>0, 2,1);
ghost->CollDetection = false;
while(true){
if (state==0){
range ++;
if (range>= origrange){
state=1;
ghost->CollDetection=true;
}
}
if (state==1){
if (shotcounter>45)anglex+=speed;
if (anglex>=360) anglex=0;
Ghost_X = origx + range*Cos(anglex);
Ghost_Y = origy + range*Sin(anglex);
shotcounter--;
if (shotcounter<=45){
if (IsOdd(shotcounter)) Ghost_CSet = CSET_DRACULA2_WARNING;
else Ghost_CSet = origcset;
if (shotcounter==0){
eweapon e = FireAimedEWeapon(ghost->Weapon, CenterX(ghost), CenterY(ghost),0, 240, WPND, SPR_DRACULA2_FIREBALL, -1, 0);
shotcounter=shotspeed;
if (Ghost_GetAttribute(ghost, 1, 0)==0) speed = (Rand(4)-2) * Cond (berserk>0, 2,1);
}
}
}
if (DRACULA2_BERSERK>0){
if (berserk==0 && Ghost_HP<=DRACULA2_BERSERK){
Game->PlaySound(SFX_SUMMON);
speed*=2;
berserk=1;
}
}
if ((!UsingItem(I_LENS))&&Ghost_HP>0){
ghost->DrawXOffset=256;
for (int i=0; i<NumIllusions; i++){
int drawangle = anglex + 360/NumIllusions*i;
Screen->DrawTile(1, origx + range*Cos(drawangle), origy + range*Sin(drawangle), ghost->Tile, sizex, sizey,Ghost_CSet, -1, -1,0, 0, 0,0,true, OP_TRANS);
}
}
else ghost->DrawXOffset=0;
if (!Ghost_Waitframe(this, ghost, false, false)){
ghost->DrawXOffset=0;
Ghost_DeathAnimation(this, ghost, GHD_SHRINK);
Quit();
}
}
}
}
const int SPR_SHELL_FIREBALL = -1;//Sprite used for fireballs
//Hides inside his invicible shell for ambush.
ffc script ShelledTurret{
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;//Weapon Damage->Additional damage cauded by getting stunned by tremors
int proximity = Ghost_GetAttribute(ghost, 0, 32);//Proximity radius.
int behaviour = Ghost_GetAttribute(ghost, 1, 0);//Baehaviour after shooting. 0 - hide back, 1 - rapid fire, 2 - run around
int sizex = Ghost_GetAttribute(ghost, 2, 4);//Tile Width
int sizey = Ghost_GetAttribute(ghost, 3, 4);//Tile Height
int delay = Ghost_GetAttribute(ghost, 4, 30);//Delay fetween firing, in frames
int walkduration = Ghost_GetAttribute(ghost, 5, 0);//Walking duration, if attrubute 2 is set to 2. 0 for infinite.
ghost->Extend=3;
Ghost_SetSize(this, ghost, sizex, sizey);
if (sizex>2 && sizey>2)Ghost_SetHitOffsets(ghost, 8, 8, 8, 8);
Ghost_SetFlag(GHF_NORMAL);
int OrigTile = ghost->OriginalTile;
int State = 0;
int haltcounter = -1;
int statecounter = delay;
int defs[18];
Ghost_StoreDefenses(ghost,defs);
Ghost_SetAllDefenses(ghost, NPCDT_BLOCK);
while(true){
if (State==0){
Ghost_ForceDir(Ghost_FaceLink(ghost));
if (statecounter>0) statecounter--;
if ((statecounter==0)&&(Distance(Link->X, Link->Y, this->X, this->Y)<=proximity)){
statecounter = delay;
Ghost_SetDefenses(ghost, defs);
State=1;
}
}
if (State==1){
if (statecounter == delay)eweapon e = FireAimedEWeapon(ghost->Weapon, Ghost_X, Ghost_Y, 0, 200, WPND, SPR_SHELL_FIREBALL, -1, 0);
if (statecounter>0) statecounter--;
if (statecounter==0){
statecounter = delay;
State=behaviour;
if (State==0)Ghost_SetAllDefenses(ghost, NPCDT_BLOCK);
if (State==2)statecounter=walkduration;
}
}
if (State==2){
haltcounter = Ghost_ConstantWalk4(haltcounter, SPD, RR, HF, HNG);
if (walkduration>0){
if (statecounter>0) statecounter--;
if (statecounter==0){
statecounter = delay;
State=0;
Ghost_SetAllDefenses(ghost, NPCDT_BLOCK);
}
}
}
Animation(ghost, OrigTile, State, 2);
Ghost_Waitframe(this, ghost);
}
}
}
void Animation(npc ghost, int origtile, int State, int numframes){
int offset = 20*State;
ghost->OriginalTile = origtile + offset;
}
int Ghost_FaceLink(npc ghost){
int cmb = ComboAt (CenterLinkX(), CenterLinkY());
int ghostcmb = ComboAt (Ghost_X+8, Ghost_Y+8);
if (ComboY(cmb)<ComboY(ghostcmb)) return DIR_UP;
else if (ComboY(cmb)>ComboY(ghostcmb)) return DIR_DOWN;
else if (ComboX(cmb)<ComboX(ghostcmb)) return DIR_LEFT;
else return DIR_RIGHT;
}
//Chorus of Mysteries Beholder
//Moves like medusa head, bouncing off screen edges and solid terrain. Sometimes stops to spawn enemies. Invincible, while moving.
ffc script BeholderCV{
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 Amplitude = Ghost_GetAttribute(ghost, 0, 24); //Y-scale of sine wave period. Set to negative for cosine wave motion.
int Period = Ghost_GetAttribute(ghost, 1, 96); //X-scale of sine wave period.
int sizex = Ghost_GetAttribute(ghost, 2, 1);//Tile Width
int sizey = Ghost_GetAttribute(ghost, 3, 1);//Tile Height
int delay = Ghost_GetAttribute(ghost, 4, 180);//Delay between spawning, in frames
int enemyspawn = Ghost_GetAttribute(ghost, 5, 42);//Id of enemy to spawn
ghost->Extend=3;
Ghost_SetSize(this, ghost, sizex, sizey);
if (sizex>2 && sizey>2)Ghost_SetHitOffsets(ghost, 8, 8, 8, 8);
Ghost_SetFlag(GHF_NORMAL);
int OrigTile = ghost->OriginalTile;
int State = 0;
int haltcounter = -1;
int statecounter = delay;
int direction = 1;
if (Ghost_X>=128) direction=2;
int AxisY = Ghost_Y; //Axis of sine wave.
int CurAngle = Rand(360);//Current angular position used for calculating sine wave position.
int anglestep = 360/Period; //Used for calculating
int defs[18];
Ghost_StoreDefenses(ghost,defs);
Ghost_SetAllDefenses(ghost, NPCDT_BLOCK);
while(true){
if (State==0){
if (direction == 1){
Ghost_ForceDir(DIR_RIGHT);
Ghost_X += SPD/100;
if (!(Ghost_CanMove(DIR_RIGHT, 1, 1, true))) direction=2;
}
else if (direction == 2){
Ghost_ForceDir(DIR_LEFT);
Ghost_X -= SPD/100;
if (!(Ghost_CanMove(DIR_LEFT, 1, 1, true))) direction=1;
}
CurAngle += anglestep;
Ghost_Y = AxisY+ Amplitude*Sin(CurAngle);
statecounter--;
if (statecounter<=60){
Ghost_SetDefenses(ghost, defs);
State=1;
}
}
if (State==1){
statecounter--;
if (statecounter<=0){
Ghost_SetAllDefenses(ghost, NPCDT_BLOCK);
State=0;
statecounter = delay;
Game->PlaySound(SFX_SUMMON);
npc r = SpawnNPC(enemyspawn);
r->X=Ghost_X;
r->Y=Ghost_Y;
}
}
BeholderAnimation(ghost, OrigTile, State, 2);
Ghost_Waitframe(this, ghost);
}
}
}
void BeholderAnimation(npc ghost, int origtile, int State, int numframes){
int offset = 20 * ghost->TileHeight;
if (State==0) offset=0;
ghost->OriginalTile = origtile + offset;
}