const int POS_WIZZROBE_STATE_TELEPORTING_IN = 1;
const int POS_WIZZROBE_STATE_TELEPORTING_OUT = 4;
const int POS_WIZZROBE_STATE_CHARGING = 2;
const int POS_WIZZROBE_STATE_FIRED = 3;
const int POS_WIZZROBE_STATE_NOT_IN_PLANE = 0;
const int SFX_ENEMY_HEAL = 25;//Sound to play, when Wizzrobe`s healing spell hits enemy for healing.
const int SFX_BLACKHOLE_POS_WIZZROBE=13;//Sound to play, when Wizrobe activates black-hole-like suction.
const int SFX_BLACKHOLE_POS_WIZZROBE_LOOP_DELAY = 20;//Delay between loop sound plays during bloack-hole - like suction.
const int SPR_POS_WIZZROBE_ENEMY_HEAL = 96;//Ssprite to display, when Wizzrobe`s healing spell hits enemy for healing.
const int POS_WIZZROBE_MAX_REROLL_COUNT = 64;//Maximum position reroll count. If exceeded Wizzrobe spawn at random position, ignoring minimum distance to Link.
const int POS_WIZZROBE_DEFAULT_SUMMON_ID = 106;//Default summoned enemy ID.
const int POS_WIZZROBE_INTRO_DURATION = 90;
//Fix Position teleporting Wizzrobe. Unlike original Wizzrobe, this variant uses up to 10 predetermined positions, picked at random, for defining spawning positions.
// Use enemy placement flags (##37-46) to define possible spawning positions.
//!\ REQUIRES LinkMovement.zh !!
global script FFWizzrobeActive{
void run(){
StartGhostZH();
Tango_Start();
__classic_zh_InitScreenUpdating();
LinkMovement_Init();
while(true) {
LinkMovement_Update1();
UpdateGhostZH1();
__classic_zh_UpdateScreenChange1();
Tango_Update1();
__classic_zh_do_z2_lantern();
if ( __classic_zc_internal[__classic_zh_SCREENCHANGED] )
{
__classic_zh_CompassBeep();
__classic_zh_ResetScreenChange();
}
Waitdraw();
LinkMovement_Update2();
UpdateGhostZH2();
Tango_Update2();
Waitframe();
}
}
}
ffc script RandPosWizzrobe{
void run(int enemyID){
npc ghost = Ghost_InitAutoGhost(this, enemyID);
int MinLinkDistance = 128 - (ghost->Homing)/2;//Minimum distance to Link when teleporting
int WPND = ghost->WeaponDamage;//Magic damage
int Teledelay = Ghost_GetAttribute(ghost, 0, 120);//Delay between teleporting
int MagicHealEnemies = Ghost_GetAttribute(ghost, 1, 0);//If magic hits enemy it heals that value
int Wpn = Ghost_GetAttribute(ghost, 2, 0);//Attack type: 0 - 1 shot, 1- 4 shots orthogonally, 2-8 shots in orthogonal and diagonal directions, 3 - summon enemies, 4 - nukes the whole screen for damage anywhere!, 5 - Aimed eweapon at Link, 6 - tripled aimed eweapon.
int EWType = Ghost_GetAttribute(ghost, 3, -1);//Weapon sprite / Enemy ID / nuke flash color
int ewSound = Ghost_GetAttribute(ghost, 4, 32);// Weapon fire sound / enemy count
int BlackHoleRange = Ghost_GetAttribute(ghost, 5, 0);//Black hole-like suction range, in pixels
int BlackHoleSpeed = Ghost_GetAttribute(ghost, 6, 0);//Black hole-like suction speed, in 1/100ths of pixel per speed
int SizeX = Ghost_GetAttribute(ghost, 7, 1);//Enemy Size X
int SizeY = Ghost_GetAttribute(ghost, 8, 1);//Enemy Size Y
int IntroCMB = Ghost_GetAttribute(ghost, 9, 0);//comboID drawn during introduction sequence, using enemy`s CSet. 0 for no intro.
ghost->Extend=3;
Ghost_SetSize(this, ghost, SizeX, SizeY);
Ghost_SetHitOffsets(ghost, 8, 8, 8, 8);
Ghost_SetFlag(GHF_NORMAL);
Ghost_SetFlag(GHF_NO_FALL);
Ghost_UnsetFlag(GHF_KNOCKBACK);
int PosCmb[10];
int maxoffset = 0;
for (int i=0;i<10;i++){
int c = 0;
while(!ComboFI(c, 37+i)){
c++;
if (c>=176)break;
}
if (c>=176)continue;
PosCmb[maxoffset] = c;
maxoffset++;
// Trace(OffsetX[i]);
}
int curpos=Rand(maxoffset);
Ghost_X=ComboX(PosCmb[curpos]);
Ghost_Y=ComboY(PosCmb[curpos]);
int origmidi = Game->GetMIDI();
int OrigTile = ghost->OriginalTile;
int State = 0;
int haltcounter = -1;
int StateCounter =Teledelay;
int dir = Ghost_Dir;
float suckx = Link->X;
float sucky = Link->Y;
int soundcounter=SFX_BLACKHOLE_POS_WIZZROBE_LOOP_DELAY;
if (IntroCMB>0){
StateCounter+=POS_WIZZROBE_INTRO_DURATION;
Game->PlayMIDI(0);
}
while(true){
if (State==POS_WIZZROBE_STATE_NOT_IN_PLANE){
ghost->DrawXOffset = 1000;
ghost->HitXOffset = 1000;
if (StateCounter>Teledelay){
Screen->DrawCombo (2, Ghost_X, Ghost_Y,IntroCMB,Ghost_TileWidth, Ghost_TileHeight,Ghost_CSet, -1, -1,0,0,0,0,0,true,OP_OPAQUE);
}
if (StateCounter == 0){
if (IntroCMB>0)Game->PlayMIDI(origmidi);
ghost->DrawXOffset = 0;
for (int r = 0; r<POS_WIZZROBE_MAX_REROLL_COUNT;r++){
curpos=Rand(maxoffset);
Ghost_X=ComboX(PosCmb[curpos]);
Ghost_Y=ComboY(PosCmb[curpos]);
if (Distance(CenterX(ghost),CenterY(ghost),CenterLinkX(),CenterLinkY()) <=MinLinkDistance) break;
}
State = POS_WIZZROBE_STATE_TELEPORTING_IN;
StateCounter = 32;
dir = WizzrobeFaceLink(ghost);
Ghost_ForceDir(dir);
}
}
if (State==POS_WIZZROBE_STATE_TELEPORTING_IN){
if(IsOdd(StateCounter)) ghost->DrawXOffset=1000;
else ghost->DrawXOffset=0;
if (StateCounter == 0){
State = POS_WIZZROBE_STATE_CHARGING;
ghost->HitXOffset = 0;
StateCounter = 32;
}
}
if (State==POS_WIZZROBE_STATE_CHARGING){
if (BlackHoleRange>0){
soundcounter--;
if (soundcounter<=0)soundcounter=SFX_BLACKHOLE_POS_WIZZROBE_LOOP_DELAY;
float dist = Distance(Ghost_X, Ghost_Y, Link->X, Link->Y);
if (dist<=BlackHoleRange){
if (soundcounter==SFX_BLACKHOLE_POS_WIZZROBE_LOOP_DELAY)Game->PlaySound(SFX_BLACKHOLE_POS_WIZZROBE);
float angle = Angle(this->X, this->Y, Link->X, Link->Y);
suckx = -BlackHoleSpeed/100*Cos(angle);
sucky = -BlackHoleSpeed/100*Sin(angle);
LinkMovement_Push2(suckx, sucky);
dist = Distance(Ghost_X, Ghost_Y, Link->X, Link->Y);
// if (dist< (BlackHoleRange/2)&& BlackHoleDrainPower>0){
// int drawlerp = Randf(1);
// int drawx = Lerp(Ghost_X, Link->X, drawlerp);
// int drawy = Lerp(Ghost_Y, Link->Y, drawlerp);
// if (BlackHoleCounterTile>0) Screen->FastTile(2, drawx, drawy, BlackHoleCounterTile, ghost->CSet, OP_OPAQUE);
// if ((StateCounter%POS_WIZZROBE_COUNTER_DRAIN_DELAY)==0){
// Game->PlaySound(SFX_POS_WIZZROBE_COUNTER_DRAIN);
// Game->DCounter[BlackHoleCounter] -= BlackHoleDrainPower;
// }
// }
}
}
if (StateCounter == 0){
State = POS_WIZZROBE_STATE_FIRED;
StateCounter = 32;
eweapon e;
if (Wpn == 0){
e = FireNonAngularEWeapon(ghost->Weapon, Ghost_X, Ghost_Y, ghost->Dir, 300, WPND, EWType,ewSound, EWF_ROTATE);
}
if (MagicHealEnemies>0){
while(e->isValid()){
for (int i=1; i<=Screen->NumNPCs(); i++){
npc h = Screen->LoadNPC(i);
if (h==ghost) continue;
if (Collision(h,e)){
h->HP+=MagicHealEnemies;
Remove(e);
Game->PlaySound(SFX_ENEMY_HEAL);
lweapon s = CreateLWeaponAt(LW_SPARKLE, h->X, h->Y);
s->UseSprite(SPR_POS_WIZZROBE_ENEMY_HEAL);
s->CollDetection=false;
}
}
Ghost_Waitframe(this, ghost);
}
}
else if (Wpn == 1){
int dirs[4]= {DIR_UP, DIR_DOWN, DIR_LEFT, DIR_RIGHT};
Game->PlaySound(ewSound);
for (int i=0;i<SizeOfArray(dirs);i++){
eweapon e = FireNonAngularEWeapon(ghost->Weapon, Ghost_X, Ghost_Y, dirs[i], 300, WPND, EWType,0, EWF_ROTATE);
}
}
else if (Wpn == 2){
int dirs[8] = {DIR_UP, DIR_RIGHTUP, DIR_RIGHT, DIR_RIGHTDOWN, DIR_DOWN, DIR_LEFTDOWN, DIR_LEFT, DIR_LEFTUP};
Game->PlaySound(ewSound);
for (int i=0;i<SizeOfArray(dirs);i++){
e = FireNonAngularEWeapon(ghost->Weapon, Ghost_X, Ghost_Y, dirs[i], 300, WPND, EWType,0, EWF_ROTATE);
}
}
else if (Wpn == 3){
Game->PlaySound(SFX_SUMMON);
for (int i=1; i<=ewSound;i++){
npc en = CreateNPCAt(Cond(EWType>0,EWType,POS_WIZZROBE_DEFAULT_SUMMON_ID), Ghost_X,Ghost_Y);
}
}
else if (Wpn == 4){
eweapon e = FireEWeapon(EW_SCRIPT10, Link->X+InFrontX(Link->Dir, 12), Link->Y+InFrontY(Link->Dir, 12), 0, 0, WPND, 22, ewSound, EWF_UNBLOCKABLE);
e->Dir = Link->Dir;
e->DrawYOffset = -1000;
SetEWeaponLifespan(e, EWL_TIMER, 1);
SetEWeaponDeathEffect(e, EWD_VANISH, 0);
for (int i=1; i<=60;i++){
if(i % 2 == 0) Screen->Rectangle(6, 0, 0, 256, 172, Cond(EWType>0,EWType,22), 1, 0, 0, 0, true, 64);
Ghost_Waitframe(this, ghost);
}
}
else if (Wpn == 5){
e = FireAimedEWeapon(ghost->Weapon, CenterX(ghost)-8, CenterY(ghost)-8, 0, 300, WPND, EWType, -1, EWF_ROTATE);
}
else if (Wpn == 6){
e = FireAimedEWeapon(ghost->Weapon, CenterX(ghost)-8, CenterY(ghost)-8, 0, 300, WPND, EWType, -1, EWF_ROTATE);
e = FireAimedEWeapon(ghost->Weapon, CenterX(ghost)-8, CenterY(ghost)-8, 0.2, 300, WPND, EWType, -1, EWF_ROTATE);
e = FireAimedEWeapon(ghost->Weapon, CenterX(ghost)-8, CenterY(ghost)-8, -0.2, 300, WPND, EWType, -1, EWF_ROTATE);
}
}
}
if (State==POS_WIZZROBE_STATE_FIRED){
if (StateCounter == 0){
State = POS_WIZZROBE_STATE_TELEPORTING_OUT;
StateCounter = 32;
}
}
if (State==POS_WIZZROBE_STATE_TELEPORTING_OUT){
if(IsOdd(StateCounter)) ghost->DrawXOffset=1000;
else ghost->DrawXOffset=0;
if (StateCounter == 0){
ghost->DrawXOffset = 1000;
ghost->HitXOffset = 1000;
State = POS_WIZZROBE_STATE_NOT_IN_PLANE;
StateCounter = Teledelay;
}
}
StateCounter--;
Ghost_ForceDir(dir);
POS_WizzrobeAnimation(ghost, OrigTile, State);
Ghost_Waitframe(this, ghost);
}
}
}
void POS_WizzrobeAnimation(npc ghost, int origtile, int state){
int offset = 0;
if (state==POS_WIZZROBE_STATE_CHARGING )offset = 20*ghost->TileHeight;
if (state==POS_WIZZROBE_STATE_FIRED )offset = 40*ghost->TileHeight;
ghost->OriginalTile = origtile + offset;
}
int WizzrobeFaceLink(npc ghost){
int angle = Angle(Ghost_X+Ghost_TileWidth*8-8,Ghost_Y+Ghost_TileHeight*8-8,CenterLinkX(),CenterLinkY());
return AngleDir4(angle);
}