//Solid moving wall trap. Instant-kills if completely closes in, but crushing against random stuff inside arena is like normal solid FFC crusher.
//Can be any size, even beyond 4*4. Uses custom rendering. Trigger secrets to blow up the Demon Wall.
//Requires Solid FFCs.zh and all it`s dependencies. Global script example uses combination of default classic.zh global, LinkMovement, needed for SolidFFFC, and Solid FFC.
//Set up 3*3 tiles for wall rendering
//Set up SolidFFCs.zh and all his dependencies
//Place FFC at top Left Corner of initial position of trap. Set velocity for movement.
//D0 NPC slot to keep track for weak spot. If you use enemy that has ghosted death animation, set D0 to it`s enemy slot so the wall will stop and don`t crush Link during death animation.
//D1 - X size of the wall, in tiles.
//D2 - Y size of the wall, in tiles.
//D3 - Top left corner of tile setup from step 1.
//D4 - death sprite, draw for each tile in wall. 0 for sbomb explosion at center.
ffc script DemonWall{
void run(int npcslot, int sizex, int sizey, int tile, int deathspr){
this->Data=FFCS_INVISIBLE_COMBO;
if (Screen->State[ST_SECRET])Quit();
int respx=-1;
int respy=-1;
int drawx=0;
int drawy=0;
int xoffset=0;
int yoffset=0;
lweapon explosion;
int boomcounter=16;
Waitframes(4);
SolidObjects[__SOLIDOBJ_FORCERESPAWNCOUNTER]=0;
npc en;
if (npcslot>0)en = Screen->LoadNPC(npcslot);
while(!Screen->State[ST_SECRET]){
if(en->isValid()){
if (en->HP>1){
//Your custom behaviour while enemy is alive goes here.
}
else{
this->Vx=0;
this->Vy=0;
boomcounter--;
if (boomcounter==0){
explosion=Screen->CreateLWeapon(LW_BOMBBLAST);
explosion->X=this->X+Rand(16*sizex)-8;
explosion->Y=this->Y+Rand(16*sizey)-8;
explosion->CollDetection=false;
boomcounter=16;
}
}
}
for (int w=0; w<sizex; w++){
drawx = this->X+16*w;
xoffset=0;
if (w>0)xoffset=1;
if (w==sizex-1) xoffset=2;
for (int h=0; h<sizey; h++){
drawy = this->Y+16*h;
yoffset=0;
if (h>0)yoffset=1;
if (h==sizey-1) yoffset=2;
Screen->FastTile(1, drawx, drawy, tile +xoffset+20*yoffset, this->CSet, OP_OPAQUE);
}
}
SolidObjects_Add(FFCNum(this), this->X, this->Y, sizex*16, sizey*16, this->Vx, this->Vy, 2);
if (SolidObjects[__SOLIDOBJ_FORCERESPAWNCOUNTER]>0 && SolidObjects[__SOLIDOBJ_CRUSHCOUNTER]>0){
Link->HP=0; //Kill Link Instantly, if DemonWall hits respawn spot.
}
Waitframe();
}
if (deathspr==0){
explosion=Screen->CreateLWeapon(LW_SBOMBBLAST);
explosion->X=this->X+sizex*8;
explosion->Y=this->Y+sizey*8;
explosion->CollDetection=false;
}
else{
for (int w=0; w<sizex; w++){
drawx = this->X+16*w;
xoffset=0;
if (w>0)xoffset=1;
if (w==sizex-1) xoffset=2;
for (int h=0; h<sizey; h++){
drawy = this->Y+16*h;
yoffset=0;
if (h>0)yoffset=1;
if (h==sizey-1) yoffset=2;
explosion=Screen->CreateLWeapon(LW_SPARKLE);
explosion->X=drawx;
explosion->Y=drawy;
explosion->UseSprite(deathspr);
explosion->CollDetection=false;
}
}
}
}
}
global script DemonWallActive{
void run(){
StartGhostZH();
Tango_Start();
__classic_zh_InitScreenUpdating();
LinkMovement_Init();
SolidObjects_Init();
while(true) {
SolidObjects_Update1();
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();
SolidObjects_Update2();
LinkMovement_Update2();
UpdateGhostZH2();
Tango_Update2();
Waitframe();
}
}
}
//Eye boss for demon wall script. Moves along the wall, fires magic lasers. Kill the eye to destroy Demon Wall
//Set up demon wall script
//Place and set up Demon_Wall_Eye onto wall, using enemy placement flags.
//Set demon wall FFC`s D0 to slot used by eye boss enemy.
ffc script Demon_Wall_Eye{
void run(int enemyID){
npc ghost = Ghost_InitAutoGhost(this, enemyID);
int SPD = ghost->Step;//movement speed along the wall.
int WPND = ghost->WeaponDamage;
int dir = Ghost_GetAttribute(ghost, 0, 0);//initial movement direction. Use No enemy fags to prevent boss from moving offscreen.
int EWType = Ghost_GetAttribute(ghost, 1, EW_MAGIC);//Projectile type
int wallslot = Ghost_GetAttribute(ghost, 2, 1);//FFC script slot for demon wall script
int firedir = Ghost_GetAttribute(ghost, 3, DIR_DOWN);//Weapopn firing direction
int Aspeed = Ghost_GetAttribute(ghost, 4, 60);//Animation/firing delay, in frames
int EWSprite = Ghost_GetAttribute(ghost, 5, -1);//Sprite used for eweapon.
int ewsizex = Ghost_GetAttribute(ghost, 6, 1);//Eweapon size, in tiles
int ewsizey = Ghost_GetAttribute(ghost, 7, 1);
ghost->Extend=3;
Ghost_SetSize(this, ghost, 2, 2);
Ghost_SetHitOffsets(ghost, 8, 8, 8, 8);
//Ghost_SetFlag(GHF_NORMAL);
Ghost_SetFlag(GHF_IGNORE_ALL_TERRAIN);
Ghost_SetFlag(GHF_NO_FALL);
int OrigTile = ghost->OriginalTile;
int State = 0;
int haltcounter = -1;
int str[] = "DemonWall";
int scr = Game->GetFFCScript(str);
ffc w = Screen->LoadFFC(wallslot);
if (w->Script!=scr){
lweapon explosion=Screen->CreateLWeapon(LW_SBOMBBLAST);
Trace(w->Script);
explosion->X=ghost->X;
explosion->Y=ghost->Y;
explosion->CollDetection=false;
ghost->HP=0;
Quit();
}
int defs[18];
Ghost_StoreDefenses(ghost,defs);
Ghost_SetAllDefenses(ghost, NPCDT_BLOCK);
while(true){
if (!Ghost_CanMove(dir, SPD/100, 0))dir=OppositeDir(dir);
Ghost_Move(dir, SPD/100, 0);
Ghost_X+=w->Vx;
Ghost_Y+=w->Vy;
haltcounter++;
if (haltcounter>240) haltcounter-=240;
if (haltcounter%(Aspeed*2)>=Aspeed){
ghost->OriginalTile=OrigTile+ghost->TileWidth;
Ghost_SetDefenses(ghost, defs);
if (haltcounter%(Aspeed*2)==Aspeed){
eweapon e = FireBigNonAngularEWeapon(EWType, CenterX(ghost)-8, CenterY(ghost)-8, DIR_DOWN, 300, WPND, EWSprite, -1, 0, ewsizex, ewsizey);
}
}
else {
// shotcounter=0;
ghost->OriginalTile=OrigTile;
Ghost_SetAllDefenses(ghost, NPCDT_BLOCK);
}
if (!Ghost_Waitframe(this, ghost, false, false)){
Ghost_DeathAnimation(this, ghost, GHD_EXPLODE);
Quit();
}
}
}
}
//Eye boss for demon wall script, variant 2. Teleports along the wall, up to 10 random positions determined by enemy placement flags, fires aimed eweapons. Kill the eye to destroy Demon Wall.
//Set up demon wall script
//Place and set up Demon_Wall_Eye spawnins positions onto wall, using enemy placement flags.
//Set demon wall FFC`s D0 to slot used by eye boss enemy.
ffc script Demon_Wall_Eye2{
void run(int enemyID){
npc ghost = Ghost_InitAutoGhost(this, enemyID);
int SPD = ghost->Step;//movement speed along the wall.
int WPND = ghost->WeaponDamage;
int dir = Ghost_GetAttribute(ghost, 0, 0);//unused
int wallslot = Ghost_GetAttribute(ghost, 1, 1);//FFC script slot for demon wall script
int sizex = Ghost_GetAttribute(ghost, 2, 1);//enemy size, X, in tiles.
int sizey = Ghost_GetAttribute(ghost, 3, 1);//enemy size, Y, in tiles.
int Aspeed = Ghost_GetAttribute(ghost, 4, 60);//Delay between teleporting and opening fire for shooting. Vulnerable only when eye is open.
int EWSprite = Ghost_GetAttribute(ghost, 5, -1);//Sprite used for eweapon.
int ewspeed = Ghost_GetAttribute(ghost, 6, 200);//Eweapon speed
int teledelay = Ghost_GetAttribute(ghost, 7, 90);//Delay between shooting snd closing eye before teleporting.
int warntime = Ghost_GetAttribute(ghost, 8, 15); //Used in enemy animation for opening and closing eye
ghost->Extend=3;
Ghost_SetSize(this, ghost, 2, 2);
Ghost_SetHitOffsets(ghost, 8, 8, 8, 8);
//Ghost_SetFlag(GHF_NORMAL);
Ghost_SetFlag(GHF_IGNORE_ALL_TERRAIN);
Ghost_SetFlag(GHF_NO_FALL);
int OrigTile = ghost->OriginalTile;
int State = 0;
int haltcounter = -1;
int str[] = "DemonWall";
int scr = Game->GetFFCScript(str);
ffc w = Screen->LoadFFC(wallslot);
if (w->Script!=scr){
lweapon explosion=Screen->CreateLWeapon(LW_SBOMBBLAST);
explosion->X=ghost->X;
explosion->Y=ghost->Y;
explosion->CollDetection=false;
ghost->HP=0;
Quit();
}
int OffsetX[10];
int OffsetY[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;
OffsetX[maxoffset] = ComboX(c) - w->X;
OffsetY[maxoffset] = ComboY(c) - w->Y;
maxoffset++;
// Trace(OffsetX[i]);
}
int curpos=Rand(maxoffset);
Ghost_X=w->X+OffsetX[curpos];
Ghost_Y=w->Y+OffsetY[curpos];
// TraceNL();
// Trace(curpos);
int shoottimer = Aspeed;
int teletimer = 0;
int Aoffset = 0;
int defs[18];
Ghost_StoreDefenses(ghost,defs);
Ghost_SetAllDefenses(ghost, NPCDT_IGNORE);
while(true){
if (shoottimer>0){
shoottimer--;
if (shoottimer==0){
Ghost_SetDefenses(ghost,defs);
eweapon e = FireAimedEWeapon(ghost->Weapon, CenterX(ghost), CenterY(ghost), 0, ewspeed, WPND, EWSprite, -1, 0);
teletimer = teledelay;
}
}
else if (teletimer>0){
teletimer--;
if (teletimer==0){
curpos=Rand(maxoffset);
// Trace(curpos);
shoottimer = Aspeed;
Ghost_SetAllDefenses(ghost, NPCDT_IGNORE);
}
}
if (teletimer>0)Aoffset = 2;
else Aoffset=0;
if ((shoottimer>0 && shoottimer<warntime)||(teletimer>0 && teletimer<warntime)) Aoffset = 1;
ghost->OriginalTile = OrigTile+Aoffset*Ghost_TileWidth;
Ghost_X=w->X+OffsetX[curpos];
Ghost_Y=w->Y+OffsetY[curpos];
if (!Ghost_Waitframe(this, ghost, false, false)){
Ghost_DeathAnimation(this, ghost, GHD_EXPLODE);
Quit();
}
}
}
}