const int SFX_THWOMP_CRASH = 3; // Sound effect for Thwomp hitting ground.
const int SFX_THWOMP_DROP = 38; //Sound effect to play, when Thwomp starts falling.
const int THWOMP_QUAKE = 30; //Quake power on thwomp land.
//A heavy stone block-like enemy that lurks on the seilinr or in the sky. When Link attempts to pass under it, the enemy falls down in attempt to crush hero. Can burst into eweapons on fall, like falling chandelier. If killed, he can turn into solid block that can be pushed once all beatable enemies are gone.
//Requires LinkMovement.zh, SolidFFC.zh and TallPushBlock script.
//Animation - 2 frames
ffc script TopDown_Thwomp{
void run(int enemyID){
npc ghost = Ghost_InitAutoGhost(this, enemyID);
int SPD = ghost->Step; //Speed of Thwomp rising after fall.
int WPND = ghost->WeaponDamage; // Damage dealt by shards form Skree
int KineticDamage = Ghost_GetAttribute(ghost, 0, 0); //Set to 1 and Thwomp will deal variable
//damage depending on the speed in the moment of hitting Link, ranging from half a heart to the original damage at terminal velocity.
int NumShards = Ghost_GetAttribute(ghost, 1, 0); //Setting to any number above 0 will turn Thwomp
//into Skree that breaks into given number of shards (Rock eweapons) upon hitting ground.
int SizeX = Ghost_GetAttribute(ghost, 2, 2); // Thwomp size, in tiles.
int SizeY = Ghost_GetAttribute(ghost, 3, 2); // X and Y, of course.
int ShardSpeed = Ghost_GetAttribute(ghost, 4, 175); //Speed of Skree`s shards.
int proximity = Ghost_GetAttribute(ghost, 5, 16); //Thwomp`s proximity trigger distance, in pixels.
int ShardSprite = Ghost_GetAttribute(ghost, 6, -1); //Sprite used for Skree's shards
int ZHeight = Ghost_GetAttribute(ghost, 7, 128);//Height position of the enemy.
int Cooldown = Ghost_GetAttribute(ghost, 8, 120);//Cooldown time between hitting ground and starting rising.
int Corpse_Combo = Ghost_GetAttribute(ghost, 9, 0);//Combo used for remnant pushable block. Requires TallPushBlock script, otherwise leaves nothing.
Ghost_SetFlag(GHF_NORMAL);
Ghost_SetFlag(GHF_NO_FALL);
Ghost_SetFlag(GHF_MOVE_OFFSCREEN);
Ghost_UnsetFlag(GHF_KNOCKBACK);
ghost->Extend=3;
Ghost_SetSize(this, ghost, SizeX, SizeY);
int State = 0;
int haltcounter = -1;
Ghost_Z=ZHeight;
int OrigDamage = ghost->Damage;
int origtile = ghost->OriginalTile;
int str1[] = "Solid_FFC";
int scr1 = Game->GetFFCScript(str1);
int str2[] = "LargeTallPushBlock";
int scr2 = Game->GetFFCScript(str2);
while(true){
if(KineticDamage>0){
int velocity = Abs(Ghost_Jump);
ghost->Damage = Clamp(OrigDamage*(velocity/GH_TERMINAL_VELOCITY), 2, OrigDamage);
}
if (State==0){
ghost->OriginalTile=origtile+Ghost_TileWidth;
int distance = DistanceSquared(CenterX(ghost)-CenterLinkX(), CenterY(ghost)-CenterLinkY());
if (distance<=proximity*proximity){
Ghost_UnsetFlag(GHF_NO_FALL);
Game->PlaySound(SFX_THWOMP_DROP);
State = 1;
}
}
if (State==1){
ghost->OriginalTile=origtile+Ghost_TileWidth*2;
if (Ghost_Z<=0){
Game->PlaySound(SFX_THWOMP_CRASH);
Screen->Quake+=THWOMP_QUAKE;
Ghost_Z=0;
State = 2;
ghost->Damage = OrigDamage;
haltcounter = Cooldown;
Ghost_SetFlag(GHF_NO_FALL);
if (NumShards>0){
float angle = 0;
float anglediff = (PI/(NumShards)*2);
for (int i=1; i<=NumShards; i++){
eweapon shard = FireEWeapon(ghost->Weapon, CenterX(ghost)-8, CenterY(ghost)-8, angle, ShardSpeed, ghost->WeaponDamage, ShardSprite, -1, 0);
if (ghost->WeaponDamage==0) shard->CollDetection=false;
angle = angle + anglediff;
}
ghost->ItemSet=0;
//Game->GuyCount[Game->GetCurScreen()]++;
Ghost_HP = -1000;
}
}
}
if (State == 2){
if (scr1>0)SolidObjects_Add(FFCNum(this), ghost->X+2, ghost->Y+2, Ghost_TileWidth*16-4, Ghost_TileHeight*16-3, 0, 0, 0);
ghost->OriginalTile=origtile+Ghost_TileWidth*2;
Ghost_Jump = 0;
haltcounter--;
if (haltcounter==0){
State = 3;
}
}
if(State == 3){
ghost->OriginalTile=origtile+Ghost_TileWidth;
Ghost_Jump = 0;
Ghost_Z+=SPD/100;
if (Ghost_Z>= ZHeight){
Ghost_Z>= ZHeight;
State = 0;
}
}
if (!Ghost_Waitframe(this, ghost, false, false)){
if (Ghost_Z==0 && scr2>0 && Corpse_Combo>0){
int args[] = {0,0,8};
ffc corpse = RunFFCScriptOrQuit(scr2, args);
corpse->Data = Corpse_Combo;
corpse->CSet = Ghost_CSet;
corpse->TileWidth = Ghost_TileWidth;
corpse->TileHeight = Ghost_TileHeight;
corpse->X = Ghost_X;
corpse->Y = Ghost_Y;
corpse->EffectWidth = Ghost_TileWidth*16;
corpse->EffectHeight = Ghost_TileHeight*16;
}
Quit();
}
}
}
}
//Generic trigger for various scripted pushable blocks.
//Place at position.
//D0 - Require the same CSet as this argument, if>0.
//D1 - ID of FFC script required to land onto for trigger.
ffc script GenericFFCPushblockTrigger{
void run (int PuzzleCSet, int pushblock_script){
this->InitD[7]=0;
while(true){
this->InitD[7]=0;
for(int i=1;i<=32;i++){
ffc n = Screen->LoadFFC(i);
if (n->Script!=pushblock_script)continue;
if (PuzzleCSet>0 && n->CSet!=PuzzleCSet) continue;
if (n->X==this->X && n->Y==this->Y) this->InitD[7]=1;
}
for(int i=1;i<=33;i++){
if (Screen->State[ST_SECRET]) break;
if (i==33){
Game->PlaySound(SFX_SECRET);
Screen->TriggerSecrets();
Screen->State[ST_SECRET]=true;
break;
}
ffc n = Screen->LoadFFC(i);
if (n->Script!=this->Script)continue;
if (n->InitD[7] == 0) break;
}
Waitframe();
}
}
}