const int TILE_AQUA1 = 7530; // The first tile of Aquamentus's default animation.
const int TILE_AQUA2 = 7570; // The first tile of Aquamentus's attacking animation.
const int SFX_AQUA_WALLCRASH = 3;
const int SFX_AQUA_STOMP = 3;
ffc script BetterAquamentus
{
void run(int enemyID)
{
npc ghost = Ghost_InitAutoGhost(this, enemyID);
Ghost_SetFlag(GHF_IGNORE_ALL_TERRAIN);
int maxHP = Ghost_HP;
int timer_attack = 180;
bool y_greater;
bool y_done;
bool turn_cset10;
bool turn_cset8;
float angle;
int choice;
ghost->Extend = 3;
Ghost_TileWidth = 2;
Ghost_TileHeight = 2;
int aspeed = ghost->ASpeed;
int original_x = Ghost_X;
int original_y = Ghost_Y;
ghost->ASpeed = 0;
Trace(aspeed);
Ghost_Waitframes(this, ghost, true, true, 30);
ghost->OriginalTile = TILE_AQUA2;
Game->PlaySound(SFX_ROAR);
Ghost_Waitframes(this, ghost, true, true, 60);
ghost->OriginalTile = TILE_AQUA1;
ghost->ASpeed = aspeed;
while (true)
{
if (Abs((Ghost_X + (0.5 * ghost->HitWidth)) - (Link->X + 8)) > 12 && Abs((Ghost_Y + (0.5 * ghost->HitHeight)) - (Link->Y + 8)) > 12);
{
Ghost_MoveTowardLink(ghost->Step * 0.01, 2);
}
if (Ghost_X <= 32 || Ghost_Y <= 16 || Ghost_Y + 32 >= 144)
{
angle = Angle(Ghost_X, Ghost_Y, original_x, original_y);
y_greater = false;
if (Ghost_Y >= original_y)
{
y_greater = true;
}
y_done = false;
while (Ghost_X < original_x || !y_done)
{
Ghost_MoveAtAngle(angle, ghost->Step * 0.04, 2);
if (y_greater && Ghost_Y <= original_y)
{
y_done = true;
}
else if (!y_greater && Ghost_Y >= original_y)
{
y_done = true;
}
BetterAqua_Ghost_Waitframe(this, ghost);
}
}
if (timer_attack <= 0)
{
if (Ghost_HP > maxHP * 0.5)
{
choice = Rand(6);
if (choice == 5)
{
Aqua_RamAttack(this, ghost, original_x, original_y, aspeed);
}
else
{
Aqua_FireballAttack(this, ghost, maxHP);
}
}
else if (Ghost_HP <= maxHP * 0.5 && Ghost_HP > maxHP * 0.25)
{
choice = Rand(6);
if (choice == 5 || choice == 4)
{
Aqua_RamAttack(this, ghost, original_x, original_y, aspeed);
}
else
{
Aqua_FireballAttack(this, ghost, maxHP);
}
}
else if (Ghost_HP <= maxHP * 0.25)
{
choice = Rand(6);
if (choice == 5 || choice == 4 || choice == 3)
{
Aqua_RamAttack(this, ghost, original_x, original_y, aspeed);
}
else
{
Aqua_FireballAttack(this, ghost, maxHP);
}
}
timer_attack = Rand(120, 240);
}
if (Ghost_HP <= maxHP * 0.5 && !turn_cset10)
{
Ghost_CSet = 10;
turn_cset10 = true;
}
if (Ghost_HP <= maxHP * 0.25 && !turn_cset8)
{
Ghost_CSet = 8;
turn_cset8 = true;
}
if (timer_attack > 0)
{
timer_attack--;
}
BetterAqua_Ghost_Waitframe(this, ghost);
}
}
}
void Aqua_FireballAttack(ffc this, npc ghost, int maxHP)
{
float angle = Angle(Ghost_X, Ghost_Y, Link->X, Link->Y);
float initangle = angle - 30;
int numshots = 3;
ghost->OriginalTile = TILE_AQUA2;
for (int i = 0; i < 30; i++)
{
BetterAqua_Ghost_Waitframe(this, ghost);
}
if (Ghost_HP <= maxHP * 0.5)
{
initangle = Choose(angle - 30, angle - 60);
numshots = 4;
}
for (int i = 0; i < numshots; i++)
{
FireEWeapon(EW_FIREBALL, Ghost_X, Ghost_Y, DegtoRad(initangle + (30 * i)), 150, ghost->WeaponDamage, -1, -1, 0);
}
for (int i = 0; i < 10; i++)
{
BetterAqua_Ghost_Waitframe(this, ghost);
}
ghost->OriginalTile = TILE_AQUA1;
}
void Aqua_RamAttack(ffc this, npc ghost, int original_x, int original_y, int aspeed)
{
int time;
float angle;
int timer_collide;
int storedDefense[18];
float jump = 4;
int t;
int t0;
int t1;
int t2;
float v;
ghost->ASpeed = aspeed * 0.5;
Ghost_StoreDefenses(ghost, storedDefense);
Ghost_SetAllDefenses(ghost, NPCDT_BLOCK);
for (int i = 0; i < 45; i++)
{
BetterAqua_Ghost_Waitframe(this, ghost);
}
angle = Angle(Ghost_X + (0.5 * ghost->HitWidth), Ghost_Y + (0.5 * ghost->HitHeight), Link->X + 8, Link->Y + 8);
//while (Ghost_CanMove(DIR_UP, ghost->Step * 0.08, 64) && Ghost_CanMove(DIR_DOWN, ghost->Step * 0.08, 64) && Ghost_CanMove(DIR_LEFT, ghost->Step * 0.08, 64))
while (!Screen->isSolid(Ghost_X + 16, Ghost_Y + 11) && !Screen->isSolid(Ghost_X + 3, Ghost_Y + 16) && !Screen->isSolid(Ghost_X + 29, Ghost_Y + 16) && !Screen->isSolid(Ghost_X + 16, Ghost_Y + 29))
{
Ghost_MoveAtAngle(angle, ghost->Step * 0.08, 4);
timer_collide++;
BetterAqua_Ghost_Waitframe(this, ghost);
}
Game->PlaySound(SFX_AQUA_WALLCRASH);
angle = Angle(Ghost_X, Ghost_Y, original_x, original_y);
t0 = (2 * jump) / GRAVITY;
t1 = (jump + TERMINAL_VELOCITY) / GRAVITY;
t2 = ((-0.5 * GRAVITY * Pow(t1, 2)) + (jump * t1)) / TERMINAL_VELOCITY;
if (t0 > t1)
{
t = t1 + t2;
}
else
{
t = t0;
}
v = Distance(Ghost_X, Ghost_Y, original_x, original_y) / t;
ghost->ASpeed = aspeed;
Ghost_Jump = jump;
for (int i = 0; i < t; i++)
{
Ghost_MoveAtAngle(angle, v, 2);
BetterAqua_Ghost_Waitframe(this, ghost);
}
Ghost_SetDefenses(ghost, storedDefense);
}
void BetterAqua_Ghost_Waitframe(ffc this, npc ghost)
{
if (ghost->Misc[0] % ghost->ASpeed == 0)
{
Game->PlaySound(SFX_AQUA_STOMP);
}
ghost->Misc[0]++;
Ghost_Waitframe(this, ghost, 1, true);
}
I wasn't entirely sure what "should back off occasionally if he gets too close to a wall" meant, and I didn't feel like playing Oracle of Seasons intro and dungeon 1 to find out. You have two tiles and two sound effects to set as constants. SFX_AQUA_STOMP can be 0 if you don't want it to make stomping noises. It needs to use built in animation, also, because the script assumes built in animation. It also uses the enemy's Step and Weapon Damage stats, so don't leave those at 0.
Edited by Lejes, 13 February 2016 - 02:50 AM.