[C]const int BARBA_QUAKE_TIME = 80; //Time in frames to shake the screen for.
const int BARBA_QUAKE_SFX = 61; //This should loop on it's own. LTTP has a good one. DO NOT SET TO BARBA'S DEFAULT ROAR SFX! IT WILL BREAK EVERYTHING!
const int BARBA_WATER_OKAY = 1; //Whether he will surface from water.
const int BARBA_PITS_OKAY = 1; //Whether he will emerge from pits.
ffc script Barba
{
void run(int enemyID)
{
// Init
npc head = Ghost_InitAutoGhost(this,enemyID);
npc body = Screen->CreateNPC(enemyID);
head->DrawXOffset+=1000;
body->DrawXOffset+=1000;
Ghost_MarkAsInUse(body);
Ghost_SetAllDefenses(body, NPCDT_IGNORE);
// Position, Resize, and store Ghost_Data
Ghost_X=256; Ghost_Y=176; //Spawn off screen;
Ghost_Transform(this,head,-1,-1,2,1);
int baseCombo=Ghost_Data;
// Flags
Ghost_SetFlag(GHF_4WAY);
Ghost_SetFlag(GHF_NO_FALL);
// Movement
int movestate;
int counter;
int basePos; //Combo
int ZVelocity=Ghost_GetAttribute(head,0,160)/100;
int segmentCount=Ghost_GetAttribute(head,1,3,1,6);
int segmentLag=Ghost_GetAttribute(head,2,10);
int segmentCombo=Ghost_Data+12;
int xoffsets[] = {-1,0,1,0,-1,0,1,0};
// int movehistory[128]; //removed as their is no use now.
// Attacking
int attackTimer;
int wDamage=head->WeaponDamage;
int wSprite=Ghost_GetAttribute(head,3,-1);
int wSound=Ghost_GetAttribute(head,4,-1);
// Misc
int dSound=head->SFX;
int frame;
int defenses[18];
Ghost_StoreDefenses(head, defenses);
// Barba Time!
do
{
if(movestate==0) //Quake
{
if(head->SFX!=BARBA_QUAKE_SFX) BarbaQuake(head);
else if(Screen->Quake==0)
{
movestate=1;
counter=0;
head->SFX=dSound;
Ghost_SetDefenses(head,defenses);
basePos = FindSpawnPoint(false,false,BARBA_WATER_OKAY,BARBA_PITS_OKAY);
BarbaHitOffsets(head);
Ghost_X=ComboX(basePos)-8;
Ghost_Y=ComboY(basePos);
}
}
else if(movestate==1) //Surfacing
{
Ghost_Data=baseCombo;
counter++;
Ghost_Z+=ZVelocity;
if(counter==segmentCount*segmentLag)
{
Ghost_Z=(segmentCount*16);
movestate=2;
counter=0;
attackTimer=0;
}
SegmentDrawing(head, basePos, counter, segmentLag, segmentCombo, xoffsets);
}
else if(movestate==2) //Attacking
{
Ghost_Data=baseCombo+4;
if(counter==32)
{
Ghost_Data=baseCombo+8;
if(attackTimer==0)
attackTimer=Rand(50,99);
if(attackTimer%8==0)
{
float x=BarbaMouthX();
float y=head->Y+InFrontY(Ghost_Dir,3);
eweapon e=FireAimedEWeapon(EW_FIREBALL, x, y, 0, 300, wDamage,wSprite,wSound,NULL); //|EWF_UNBLOCKABLE); No... and never again rapid fire unblockable is a bad idea.
}
attackTimer--;
}
else if(counter==48)
{
movestate=3;
counter=segmentCount*segmentLag;
}
if(attackTimer==0)
counter++;
SegmentDrawing(head, basePos, segmentCount*segmentLag, segmentLag, segmentCombo, xoffsets);
}
else if(movestate==3) //Submerging
{
Ghost_Data=baseCombo;
counter--;
Ghost_Z-=ZVelocity;
if(counter<=0)
{
movestate=0;
counter=0;
Ghost_Z=0;
Ghost_X=256+Ghost_TileWidth;
}
SegmentDrawing(head, basePos, counter, segmentLag, segmentCombo, xoffsets);
}
frame++;
if(frame%8==0)
{
//pushfront and loop front to back
int front = xoffsets[0];
memmove(xoffsets, 0, xoffsets, 1, 7);
xoffsets[7]=front;
frame=0;
}
BarbaWaitframe(this,head,body,basePos);
} while(Ghost_HP>0)
if(movestate==2)
counter=segmentCount*segmentLag;
BarbaExplode(this, head, body, counter, segmentLag, segmentCombo, xoffsets, basePos);
}
void BarbaQuake(npc head)
{
Screen->Quake=BARBA_QUAKE_TIME;
head->SFX=BARBA_QUAKE_SFX;
Ghost_SetAllDefenses(head,NPCDT_IGNORE);
}
int BarbaMouthX()
{
int aimx=Ghost_X+8;
return aimx+InFrontX(Ghost_Dir, 3);
}
void BarbaHitOffsets(npc head)
{
if(Ghost_Dir==DIR_LEFT)
Ghost_SetHitOffsets(head,0,0,0,.25);
else if(Ghost_Dir==DIR_RIGHT)
Ghost_SetHitOffsets(head,0,0,.25,0);
else // if(Ghost_Dir==DIR_UP || Ghost_Dir==DIR_DOWN);
Ghost_SetHitOffsets(head,0,0,.25,.25);
}
void BarbaWaitframe(ffc this, npc head, npc body, int basePos)
{
body->X=ComboX(basePos);
if(IsSideview())
{
body->Y=160;
body->Jump=0; //keep it from falling do to sideview gravity
if(Ghost_X+8>=Link->X) Ghost_Dir=DIR_LEFT;
else Ghost_Dir=DIR_RIGHT;
}
else
{
body->Y=ComboY(basePos);
Ghost_Dir=RadianAngleDir4(ArcTan(Link->X-(Ghost_X+8),Link->Y-Ghost_Y));
}
body->HitZHeight=Ghost_Z;
Ghost_Waitframe(this,head,false,false);
}
void BarbaExplode(ffc this, npc head, npc body, int counter, int segmentLag, int segmentCombo, int xoffsets, int basePos) //Custom Death cause why not? o_O
{
//Miscellaneous Crap that has to be done first.
body->ItemSet=IS_NONE;
body->HP=HP_SILENT;
body->X=1024;
__DeathAnimStart(this, head);
__DeathAnimSFX(head->ID, head->X);
__Ghost_FlashCounter=10000; //Should last long enough.
int baseX=ComboX(basePos);
int baseY=ComboY(basePos);
int segmentCount = Div(counter,segmentLag);
int layer=3; int x; int y; int x2; int y2;
int timer;
int j=0;
if(!IsSideview())
{
head->DrawXOffset-=1000;
Ghost_Y-=Ghost_Z;
Ghost_Z=0;
}
lweapon explosion;
while(j<segmentCount)
{
for(int i=j; i < segmentCount; i++)
{
x = baseX+xoffsets[i];
y = Cond(IsSideview(),160,baseY)-16*i;
y -= Ghost_Y%16;
if(i==j)
{
x2=x;
y2=y;
}
Screen->FastCombo(layer,x,y-2,segmentCombo+Ghost_Dir,Ghost_CSet,128);
}
timer++;
if(timer%16==0)
{
explosion=Screen->CreateLWeapon(LW_BOMBBLAST);
explosion->X=x2;
explosion->Y=y2;
explosion->CollDetection=false;
j++;
}
Ghost_SetPosition(this, head); // Make sure it doesn't wander off
__Ghost_UpdateFlashing(this, head);
Ghost_WaitframeLight(this,head);
}
baseX=Ghost_X+head->DrawXOffset;
baseY=Ghost_Y+head->DrawYOffset;
// One explosion every 16 frames, 15 times
for(int i=0; i<15; i++)
{
explosion=Screen->CreateLWeapon(LW_BOMBBLAST);
explosion->X=baseX+Rand(16*Ghost_TileWidth)-8;
explosion->Y=baseY+Rand(16*Ghost_TileHeight)-8;
explosion->CollDetection=false;
for(int j=0; j<16; j++)
{
Ghost_SetPosition(this, head); // Make sure it doesn't wander off
__Ghost_UpdateFlashing(this, head);
Ghost_WaitframeLight(this, head);
}
}
__DeathAnimEnd(this, head);
}
void SegmentDrawing(npc head, int basePos, int counter, int segmentLag, int segmentCombo, int xoffsets)
{
int baseX=ComboX(basePos);
int baseY=Cond(IsSideview(),160,ComboY(basePos));
int segmentCount = Div(counter,segmentLag);
int layer=2;
int x; int y;
for(int i; i < segmentCount; i++)
{
x = baseX+xoffsets[i];
y = baseY-(16*i);
if(!IsSideview() && (i*16) >= GH_DRAW_OVER_THRESHOLD) //additional segments have a drawover threshold.
{
layer=4;
}
y-=Ghost_Z%16;
Screen->FastCombo(layer,x,y-2,segmentCombo+Ghost_Dir,Ghost_CSet,128);
}
int w=1;
if(Ghost_Dir==DIR_LEFT||Ghost_Dir==DIR_RIGHT) w=2;
x-=8;
y=baseY-Ghost_Z;
layer=Cond(Ghost_Z>=GH_DRAW_OVER_THRESHOLD,4,2);
Screen->DrawCombo(4,x,y-2,Ghost_Data+Ghost_Dir,w,1,Ghost_CSet,-1,-1,0,0,0,0,0,true,128);
}
}[/C]
example quest
Lot of issues here, best to turn on collision hitbox cheat and see for yourself what's happening. Should reproduce the battle in sideview perfectly, but it does not.
edit: Fixed!