const int SPR_FFACIDHANDLA_ACID_PUDDLE = 92;//Sprite used for AcidHandla`s puddles of acid.
const int SCREEN_D_ACIDHANDLA_STATUS_EFFECT = 0;//Screen D used for status effects caused by mists generated by Acidhandla
const int C_ACIDHANDLA_STATUS_CONFUSE = 0x52;//colors of status inducing mists - Confuse - swap directions input
const int C_ACIDHANDLA_STATUS_JINX_B = 0x72;//Button jinx - B
const int C_ACIDHANDLA_STATUS_JINX_A = 0x82;//Button jinx - A
const int C_ACIDHANDLA_STATUS_ANTIMAGIC = 0x102;//Strips Link of all MP and prevents regeneration.
const int FF_ACIDHANDLA_ACID_DURATION = 120;//Duration of acid puddles before decomposing into something harmless. -1 - permanent.
//FFAcidhandla
//Extended variant of Acidhandla by MoscowModder with more customizability. Moves and fires like a normal 4, or 8 headed boss. severed heads create damaging acid puddles. Can create mist that induces status effects to Link. When all heads are severes, it can regrow spare ones (1-2 times)
//Uses 2 enemy slots, 1 for core, 1 or head. If core is killed first, all heads are gone instantly and vice versa.
ffc script FFAcidhandla{
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;
// Initialize
ghost->Extend=3;
Ghost_SetFlag(GHF_NO_FALL);
Ghost_SetFlag(GHF_NORMAL);
Ghost_SetFlag(GHF_8WAY);
Ghost_UnsetFlag(GHF_KNOCKBACK);
int firerate = Ghost_GetAttribute(ghost, 0, 60);//Delay batween firing EWeapons, in frames.
int size = Ghost_GetAttribute(ghost, 1, 1);//Enemy size and number of heads, 1 - 1x1(4 heads), 2- 2x2(8 heads), 3 -3x3(12 heads), 4 - 4x4(16 heads)
int speedinc = Ghost_GetAttribute(ghost, 2, 8);//Speed increase modifier with each head killed, stacked additively
int headID = Ghost_GetAttribute(ghost, 3, enemyID+1);//Enemy ID for heads, uses next ID in list by default, must use "Other" enemy type
int WPNS = Ghost_GetAttribute(ghost, 4, -1);//Sprite used by fired EWeapons.
int acid = Ghost_GetAttribute(ghost, 5, 120);//Delay for severed head spots between generating acid puddles, in frames.
int aciddam = Ghost_GetAttribute(ghost, 6, Ceiling(WPND/2));//Damage caused by stepping into acid, in 1/4th of heart, afterward acid decomposes/disappears.
int statuseffects = Ghost_GetAttribute(ghost, 7, 31);//Status effects - add together: 1 - Confusion, 2 - magic drain, 4 - Sword Jinx, 8 - Item Jinx, 16 - Blind (white opaque flash across screen.)
int statustimer = Ghost_GetAttribute(ghost, 8, 120);//Delay between status effect switching, in frames.
int regrowcount = Ghost_GetAttribute(ghost, 9, 0);//Number of times AcidHandla can regrow heads after slicing them all.
ghost->Extend=3;
Ghost_SetSize(this, ghost, size, size);
Ghost_SpawnAnimationPuff(this, ghost);
int OrigTile = ghost->OriginalTile;
int state = 0;
int statecounter=firerate;
if (size>4)size=4;
int haltcounter=0;
int speedmod = 0;
int statuscounter = statustimer;
Screen->D[SCREEN_D_ACIDHANDLA_STATUS_EFFECT]=0;
eweapon e;
//Spawn heads
int numheads = size*4;
npc heads[16];
int offsetX[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int offsetY[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int dirs[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int offsetX1[16] = {0, -16,16,0,0,0,0,0,0,0,0,0,0,0,0,0};
int offsetY1[16] = {-16, 0,0,16,0,0,0,0,0,0,0,0,0,0,0,0};
int dirs1[16] = {0,2,3,1,0,0,0,0,0,0,0,0,0,0,0,0};
int dirs2[16] = {0,0,2,3,2,3,1,1,0,0,0,0,0,0,0,0};
int offsetX2[16] = {0, 16,-16,32,-16,32,0,16,0,0,0,0,0,0,0,0};
int offsetY2[16] = {-16, -16,0,0,16,16,32,32,0,0,0,0,0,0,0,0};
int dirs3[16] = {0,0,0,2,3,2,3,2,3,1,1,1,0,0,0,0};
int offsetX3[16] = {0, 16,32,-16,48,-16,48,-16,48,0,16,32,0,0,0,0};
int offsetY3[16] = {-16, -16,-16,0,0,16,16,32,32,48,48,48,0,0,0,0};
int dirs4[16] = {0,0,0,0,2,3,2,3,2,3,2,3,1,1,1,1};
int offsetX4[16] = {0, 16,32,48,-16,64,-16,64,-16,64,-16,64,0,16,32,48};
int offsetY4[16] = {-16, -16,-16,-16,0,0,16,16,32,32,48,48,64,64,64,64};
int acidtimer[16];
int Ghost_MaxHP = Ghost_HP;
for (int i=0; i<numheads; i++){
acidtimer[i]=acid;
heads[i]=SpawnNPC(headID);
if (size==4){
offsetX[i]=offsetX4[i];
offsetY[i]=offsetY4[i];
dirs[i]=dirs4[i];
}
else if (size==3){
offsetX[i]=offsetX3[i];
offsetY[i]=offsetY3[i];
dirs[i]=dirs3[i];
}
else if (size==2){
offsetX[i]=offsetX2[i];
offsetY[i]=offsetY2[i];
dirs[i]=dirs2[i];
}
else{
offsetX[i]=offsetX1[i];
offsetY[i]=offsetY1[i];
dirs[i]=dirs1[i];
}
SetEnemyProperty(heads[i], ENPROP_X, Ghost_X+offsetX[i]);
SetEnemyProperty(heads[i], ENPROP_Y, Ghost_Y+offsetY[i]);
SetEnemyProperty(heads[i], ENPROP_DIR, dirs[i]);
SetEnemyProperty(heads[i], ENPROP_CSET, Ghost_CSet);
}
Ghost_Waitframe(this, ghost);
Ghost_Waitframe(this, ghost);
Ghost_Waitframe(this, ghost);
Ghost_Waitframe(this, ghost);
while(true) {
speedmod=0;
for (int i=0; i<numheads; i++){
if (heads[i]->isValid()){
SetEnemyProperty(heads[i], ENPROP_X, Ghost_X+offsetX[i]);
SetEnemyProperty(heads[i], ENPROP_Y, Ghost_Y+offsetY[i]);
SetEnemyProperty(heads[i], ENPROP_DIR, dirs[i]);
}
else speedmod+=speedinc;
if (speedmod==(numheads*speedinc)){
if (regrowcount>0){
regrowcount--;
speedmod=0;
for (int i=0; i<numheads; i++){
acidtimer[i]=acid;
heads[i]=SpawnNPC(headID);
SetEnemyProperty(heads[i], ENPROP_X, Ghost_X+offsetX[i]);
SetEnemyProperty(heads[i], ENPROP_Y, Ghost_Y+offsetY[i]);
SetEnemyProperty(heads[i], ENPROP_DIR, dirs[i]);
SetEnemyProperty(heads[i], ENPROP_CSET, Ghost_CSet);
}
Ghost_Waitframe(this, ghost);
Ghost_Waitframe(this, ghost);
Ghost_Waitframe(this, ghost);
Ghost_Waitframe(this, ghost);
}
else Ghost_HP=0;
}
}
haltcounter = Ghost_VariableWalk8(haltcounter, SPD+speedmod, RR, HF, HNG, 15);
statecounter--;
if (statecounter==0){
for (int i=0; i<numheads; i++){
if (!heads[i]->isValid()) continue;
if (WPND==0)continue;
if (ghost->Weapon==EW_FIREBALL) e = FireAimedEWeapon(ghost->Weapon,heads[i]->X , heads[i]->Y, 0, 150, WPND, WPNS, -1, EWF_ROTATE);
else e = FireNonAngularEWeapon (ghost->Weapon, heads[i]->X , heads[i]->Y, dirs[i], 200, WPND, WPNS, -1, EWF_ROTATE);
}
statecounter=firerate;
}
if (acid>0)acidtimer--;
if (acidtimer<=0){
for (int i=0; i<numheads; i++){
if (heads[i]->isValid())continue;
e = FireNonAngularEWeapon (EW_SCRIPT1, Ghost_X + offsetX[i] , Ghost_Y + offsetY[i], 0, 0, aciddam, SPR_FFACIDHANDLA_ACID_PUDDLE, -1, EWF_UNBLOCKABLE);
SetEWeaponDeathEffect(e, EWD_VANISH, 0);
SetEWeaponLifespan(e, EWL_TIMER, FF_ACIDHANDLA_ACID_DURATION);
acidtimer=acid;
}
}
if (speedmod>0 && statustimer>0){
statuscounter--;
if (statuscounter==0){
Screen->D[SCREEN_D_ACIDHANDLA_STATUS_EFFECT]=Rand(6);
if (((1<<Screen->D[SCREEN_D_ACIDHANDLA_STATUS_EFFECT])&statuseffects)==0)Screen->D[SCREEN_D_ACIDHANDLA_STATUS_EFFECT]=0;
statuscounter =statustimer;
}
}
FFAcidHandlaStatusUpdate(Screen->D[SCREEN_D_ACIDHANDLA_STATUS_EFFECT]);
if (!Ghost_Waitframe(this, ghost, false, false)){
Screen->D[SCREEN_D_ACIDHANDLA_STATUS_EFFECT]=0;
for (int i=0; i<numheads; i++){
if (heads[i]->isValid())SetEnemyProperty(heads[i], ENPROP_HP, 0);
}
Ghost_DeathAnimation(this, ghost, GHD_EXPLODE);
Quit();
}
}
}
}
void FFAcidHandlaStatusUpdate(int status){
if (status==1){ //Credit goes to Mero for original code.
Screen->Rectangle(6, 0, 0, 256, 176, C_ACIDHANDLA_STATUS_CONFUSE, 1, 1, 1, 0, true, OP_TRANS);
if(Link->InputUp != Link->InputDown)
{
Link->InputUp = !Link->InputUp;
Link->InputDown = !Link->InputDown;
}
if(Link->InputLeft != Link->InputRight)
{
Link->InputLeft = !Link->InputLeft;
Link->InputRight = !Link->InputRight;
}
}
if (status==2){
Screen->Rectangle(6, 0, 0, 256, 176, C_ACIDHANDLA_STATUS_ANTIMAGIC, 1, 1, 1, 0, true, OP_TRANS);
Link->MP=0;
}
if (status==3){
Screen->Rectangle(6, 0, 0, 256, 176, C_ACIDHANDLA_STATUS_JINX_A, 1, 1, 1, 0, true, OP_TRANS);
Link->SwordJinx=2;
}
if (status==4){
Screen->Rectangle(6, 0, 0, 256, 176, C_ACIDHANDLA_STATUS_JINX_B, 1, 1, 1, 0, true, OP_TRANS);
Link->ItemJinx=2;
}
if (status==5){
Screen->Rectangle(6, 0, 0, 256, 176, 1, 1, 1, 1, 0, true, OP_OPAQUE);
}
}