const int SFX_FF_Z1_TRAP_BOUNCE = 57;//Sound to play, when trap hits unwalkable combo or enemy.
const int SFX_FF_Z1_TRAP_LAUNCH = 17;//Sound to play, when trap detects Link and launches.(NEW!!)
//Z1 line of sight trap. Waits until Link is within it`s line of sight (or limited one, depending on settings) and attacks. It takes time for trap to reset after launch attack.
ffc script FF_Z1_LOS_Trap{
void run(int enemyID){
npc ghost = Ghost_InitAutoGhost(this, enemyID);
int HF = ghost->Homing;
int HR = ghost->Haltrate;
int RR = ghost->Rate;
int HNG = ghost->Hunger;
int SPD = ghost->Step;
int WPND = ghost->WeaponDamage;
int HorizRange = Ghost_GetAttribute(ghost, 0, 0);//Range for horizontal sight.
int VertRange = Ghost_GetAttribute(ghost, 1, 0);//Range for vertical sight.
int DiagSlashRange = Ghost_GetAttribute(ghost, 2, 0);//Range for "/" diagonal sight.
int DiagBackslashRange = Ghost_GetAttribute(ghost, 3, 0);//Range for "\" diagonal sight.
int walkflags = Ghost_GetAttribute(ghost, 4, 0);//Add together: 1 - can phase through solid combos, 2- can move across water, 4- can move over pits.
int RechargeStepSpeedModifier = Ghost_GetAttribute(ghost, 5, 50);//Retraction precentage speed modifier.
int sizex = Ghost_GetAttribute(ghost, 6, 1);//X Size
int sizey = Ghost_GetAttribute(ghost, 7, 1);//Y size
int Proximity = Ghost_GetAttribute(ghost, 8, 8);//Proximity margin.
int enemycollision = Ghost_GetAttribute(ghost, 9, 0);//>0 - collides with enemies.
ghost->Extend=3;
Ghost_SetSize(this, ghost, sizex, sizey);
Ghost_SetFlag(GHF_NORMAL);
Ghost_UnsetFlag(GHF_KNOCKBACK);
Ghost_SetFlag(GHF_NO_FALL);
int OrigTile = ghost->OriginalTile;
int State = 0;
int statecounter = 0;
int haltcounter = -1;
if ((walkflags&1)>0) Ghost_SetFlag(GHF_IGNORE_SOLIDITY);
if ((walkflags&2)>0) Ghost_SetFlag(GHF_IGNORE_WATER);
if ((walkflags&4)>0) Ghost_SetFlag(GHF_IGNORE_PITS);
int offsetX = 0;
int offsetY = 0;
int origx = Ghost_X;
int origy = Ghost_Y;
int angle = 0;
int limit = 0;
int dist = 0;
int dir =-1;
int defs[18];
Ghost_StoreDefenses(ghost,defs);
while(true){
if (State==0){
angle = Angle(CenterLinkX(), CenterLinkY(), CenterX(ghost), CenterY(ghost));
dist = Distance(CenterLinkX(), CenterLinkY(), CenterX(ghost), CenterY(ghost));
if (VertRange>0){
if ((Abs (CenterLinkX()-CenterX(ghost))<Proximity) && (Abs (CenterLinkY()-CenterY(ghost))<=HorizRange)){
Game->PlaySound(SFX_FF_Z1_TRAP_LAUNCH);
if (CenterLinkY() <= CenterY(ghost)){
Ghost_Vy = -SPD/100;
limit= VertRange;
dir=DIR_UP;
State=1;
}
else{
Ghost_Vy = SPD/100;
limit= VertRange;
dir=DIR_DOWN;
State=1;
}
}
}
if (HorizRange>0){
if ((Abs (CenterLinkY()-CenterY(ghost))<Proximity) && (Abs (CenterLinkX()-CenterX(ghost))<=HorizRange)){
Game->PlaySound(SFX_FF_Z1_TRAP_LAUNCH);
if (CenterLinkX() >= CenterX(ghost)){
Ghost_Vx = SPD/100;
limit= HorizRange;
dir=DIR_RIGHT;
State=1;
}
else{
Ghost_Vx = -SPD/100;
limit= HorizRange;
dir=DIR_LEFT;
State=1;
}
}
}
if (DiagSlashRange>0){
if ((CenterLinkX()-CenterX(ghost)<=-CenterLinkY()+CenterY(ghost)+Proximity)&&(CenterLinkX()-CenterX(ghost)>=-CenterLinkY()+CenterY(ghost)-Proximity)){
Game->PlaySound(SFX_FF_Z1_TRAP_LAUNCH);
if (CenterLinkX() <= CenterX(ghost)){
Ghost_Vx = -SPD/100;
Ghost_Vy = SPD/100;
limit= DiagSlashRange;
dir = DIR_LEFTDOWN;
State=1;
}
else{
Ghost_Vx = SPD/100;
Ghost_Vy = -SPD/100;
limit= DiagSlashRange;
dir = DIR_RIGHTUP;
State=1;
}
}
}
if (DiagBackslashRange>0){
if ((CenterLinkX()-CenterX(ghost)<=CenterLinkY()-CenterY(ghost)+Proximity)&&(CenterLinkX()-CenterX(ghost)>=CenterLinkY()-CenterY(ghost)-Proximity)){
Game->PlaySound(SFX_FF_Z1_TRAP_LAUNCH);
if (CenterLinkX() >= CenterX(ghost)){
Ghost_Vx = SPD/100;
Ghost_Vy = SPD/100;
limit= DiagBackslashRange;
dir = DIR_RIGHTDOWN;
State=1;
}
else{
Ghost_Vx = -SPD/100;
Ghost_Vy = -SPD/100;
limit= DiagBackslashRange;
dir = DIR_LEFTUP;
State=1;
}
}
}
}
if (State==1){
offsetX +=Abs(Ghost_Vx);
offsetY +=Abs(Ghost_Vy);
if ((offsetX >=limit) || (offsetY>= limit)){
Ghost_Vx*=(-RechargeStepSpeedModifier/100);
Ghost_Vy*=(-RechargeStepSpeedModifier/100);
State=2;
}
if (!Ghost_CanMove(dir, 1, 1)){
Game->PlaySound(SFX_FF_Z1_TRAP_BOUNCE);
Ghost_Vx*=(-RechargeStepSpeedModifier/100);
Ghost_Vy*=(-RechargeStepSpeedModifier/100);
Ghost_SetFlag(GHF_IGNORE_ALL_TERRAIN);
State=2;
}
for (int i=1;i<=Screen->NumNPCs();i++){
if (enemycollision==0)break;
npc n = Screen->LoadNPC(i);
if (n==ghost)continue;
if (Collision(n,ghost)){
Game->PlaySound(SFX_FF_Z1_TRAP_BOUNCE);
Ghost_Vx*=(-RechargeStepSpeedModifier/100);
Ghost_Vy*=(-RechargeStepSpeedModifier/100);
State=2;
}
}
}
if (State==2){
if (Ghost_Vx!=0)offsetX -=Abs(Ghost_Vx);
if (Ghost_Vy!=0)offsetY -=Abs(Ghost_Vy);
if (offsetX<=0 && offsetY<=0){
Ghost_X=origx;
Ghost_UnsetFlag(GHF_IGNORE_ALL_TERRAIN);
if ((walkflags&1)>0) Ghost_SetFlag(GHF_IGNORE_SOLIDITY);
if ((walkflags&2)>0) Ghost_SetFlag(GHF_IGNORE_WATER);
if ((walkflags&4)>0) Ghost_SetFlag(GHF_IGNORE_PITS);
Ghost_Y=origy;
Ghost_Vx=0;
Ghost_Vy=0;
offsetX=0;
offsetY=0;
dir=-1;
State=0;
}
}
Ghost_Waitframe(this, ghost);
}
}
}
//Moves back and forth, turning 180 degrees on collision with obstacles and enemies.
ffc script FF_Constant_Trap{
void run(int enemyID){
npc ghost = Ghost_InitAutoGhost(this, enemyID);
int HF = ghost->Homing;
int HR = ghost->Haltrate;
int RR = ghost->Rate;
int HNG = ghost->Hunger;
int SPD = ghost->Step;
int WPND = ghost->WeaponDamage;
int Dir = Ghost_GetAttribute(ghost, 0, 0);//Starting direction (0-7).
int sizex = Ghost_GetAttribute(ghost, 1, 1);//X Size
int sizey = Ghost_GetAttribute(ghost, 2, 1);//Y size
int walkflags = Ghost_GetAttribute(ghost, 3, 0);//Add together: 1 - can phase through solid combos, 2- can move across water, 4- can move over pits.
int enemycollision = Ghost_GetAttribute(ghost, 4, 0);//>0 - collides with enemies.
ghost->Extend=3;
Ghost_SetSize(this, ghost, sizex, sizey);
Ghost_SetFlag(GHF_NORMAL);
Ghost_UnsetFlag(GHF_KNOCKBACK);
Ghost_SetFlag(GHF_NO_FALL);
int OrigTile = ghost->OriginalTile;
int State = 0;
int statecounter = 0;
int haltcounter = -1;
if ((walkflags&1)>0) Ghost_SetFlag(GHF_IGNORE_SOLIDITY);
if ((walkflags&2)>0) Ghost_SetFlag(GHF_IGNORE_WATER);
if ((walkflags&4)>0) Ghost_SetFlag(GHF_IGNORE_PITS);
int defs[18];
Ghost_StoreDefenses(ghost,defs);
while(true){
Ghost_Move(Dir,SPD/100, 1);
if (!Ghost_CanMove(Dir, SPD/100, 1)){
Game->PlaySound(SFX_FF_Z1_TRAP_BOUNCE);
Dir = OppositeDir(Dir);
}
for (int i=1;i<=Screen->NumNPCs();i++){
if (enemycollision==0)break;
npc n = Screen->LoadNPC(i);
if (n==ghost)continue;
if (Collision(n,ghost)){
Game->PlaySound(SFX_FF_Z1_TRAP_BOUNCE);
Dir = OppositeDir(Dir);
}
}
Ghost_Waitframe(this, ghost);
}
}
}
const int SFX_CCIRCULUM_TRAP_BOUNCE = 57;//Sound to play, when trap hits unwalkable combo or enemy.
const int SFX_CCIRCULUM_TRAP_LAUNCH = 17;//Sound to play, when trap detects Link and launches.(NEW!!)
//Circulum Line of Sight Trap. Waits until Link is inside his line of sight - arc of specific radius, length and width - and attacks by moving in circular pattern. AFter hitting it`s limits, unwalkable combo or enemy, it returns to original position, again moving in circle.
ffc script Circulum_LOS_Trap{
void run(int enemyID){
npc ghost = Ghost_InitAutoGhost(this, enemyID);
int SPD = ghost->Step;
int Radius = Ghost_GetAttribute(ghost, 0, 48);//Circle radius.
int angle = Ghost_GetAttribute(ghost, 1, 0)+360;//Starting angle.
int anglerange = Ghost_GetAttribute(ghost, 2, 180);//Proximity arc length.
int CCW = Ghost_GetAttribute(ghost, 3, 0);//0 - clockwise movement, 1- anti-clockwise movement, 2 - depending on Link`s positon, chosing shortest circular route.
int walkflags = Ghost_GetAttribute(ghost, 4, 0);//Add together: 1 - can phase through solid combos, 2- can move across water, 4- can move over pits.
int RechargeStepSpeedModifier = Ghost_GetAttribute(ghost, 5, 50);//Retraction precentage speed modifier.
int sizex = Ghost_GetAttribute(ghost, 6, 1);//X Size
int sizey = Ghost_GetAttribute(ghost, 7, 1);//Y size
int Proximity = Ghost_GetAttribute(ghost, 8, 8);//Proximity margin.
int enemycollision = Ghost_GetAttribute(ghost, 9, 0);//>0 - collides with enemies.
ghost->Extend=3;
Ghost_SetSize(this, ghost, sizex, sizey);
Ghost_SetFlag(GHF_NORMAL);
Ghost_UnsetFlag(GHF_KNOCKBACK);
Ghost_SetFlag(GHF_NO_FALL);
int OrigTile = ghost->OriginalTile;
int State = 0;
int statecounter = 0;
int haltcounter = -1;
int anglebound = 0;
if ((walkflags&1)>0) Ghost_SetFlag(GHF_IGNORE_SOLIDITY);
if ((walkflags&2)>0) Ghost_SetFlag(GHF_IGNORE_WATER);
if ((walkflags&4)>0) Ghost_SetFlag(GHF_IGNORE_PITS);
int angleoffset = 0;
int linkangle = 0;
int limit = 0;
int anglespeed = 0;
int dist=0;
int startangle=angle;
int origX = Ghost_X;
int origY = Ghost_Y;
Ghost_X = Ghost_X+Radius*Cos(angle);
Ghost_Y = Ghost_Y+Radius*Sin(angle);
int CollX = 0;
int CollY = 0;
int leftangle = angle;
int rightangle = angle;
if (CCW==0||CCW==2)leftangle=angle-anglerange;
if (CCW==1||CCW==2)rightangle=angle-anglerange;
int defs[18];
Ghost_StoreDefenses(ghost,defs);
while(true){
if (State==0){
linkangle = Angle(CenterLinkX(), CenterLinkY(), origX+Ghost_TileWidth*8, origY+Ghost_TileHeight*8)+540;
dist = Distance(CenterLinkX(), CenterLinkY(), origX+Ghost_TileWidth*8, origY+Ghost_TileHeight*8);
if ((dist>=(Radius-Proximity)) && (dist<=(Radius+Proximity))){
if ((Abs(linkangle-angle))<=anglerange){
Game->PlaySound(SFX_CCIRCULUM_TRAP_LAUNCH);
if (CCW==2){
if (linkangle>angle) anglespeed = SPD/100;
else anglespeed = -SPD/100;
}
else anglespeed = Cond(CCW>0,-SPD/100, SPD/100);
State=1;
}
}
}
if (State==1){
angleoffset += Abs(anglespeed);
angle+=anglespeed;
Ghost_X = origX+Radius*Cos(angle);
Ghost_Y = origY+Radius*Sin(angle);
if (angleoffset>=anglerange){
anglespeed*=(-RechargeStepSpeedModifier/100);
while(angleoffset>360)angleoffset-=360;
State=2;
}
if (anglespeed<0){
CollX = CenterX(ghost)+sizex*8*Cos(angle-90);
CollY = CenterY(ghost)+sizey*8*Sin(angle-90);
}
else{
CollX = CenterX(ghost)+sizex*8*Cos(angle+90);
CollY = CenterY(ghost)+sizey*8*Sin(angle+90);
}
if (!Ghost_CanMovePixel(CollX, CollY)){
Game->PlaySound(SFX_CCIRCULUM_TRAP_BOUNCE);
while(angleoffset>360)angleoffset-=360;
anglespeed*=(-RechargeStepSpeedModifier/100);
State=2;
}
for (int i=1;i<=Screen->NumNPCs();i++){
if (enemycollision==0)break;
npc n = Screen->LoadNPC(i);
if (n==ghost)continue;
dist = Distance(CenterX(ghost), CenterY(ghost), CenterX(n), CenterY(n));
if (dist<=Min(sizex,sizey)+Min(n->TileWidth, n->TileHeight)){
Game->PlaySound(SFX_CCIRCULUM_TRAP_BOUNCE);
while(angleoffset>360)angleoffset-=360;
anglespeed*=(-RechargeStepSpeedModifier/100);
State=2;
}
}
}
if (State==2){
angleoffset -= Abs(anglespeed);
angle+=anglespeed;
Ghost_X = origX+Radius*Cos(angle);
Ghost_Y = origY+Radius*Sin(angle);
if (angleoffset<=0){
angle = startangle;
angleoffset=0;
Ghost_X = origX+Radius*Cos(angle);
Ghost_Y = origY+Radius*Sin(angle);
State=0;
}
}
Ghost_Waitframe(this, ghost);
}
}
}
//Moves in circles, turning 180 degrees on collision with obstacles and enemies.
ffc script Circulum_Constant_Trap{
void run(int enemyID){
npc ghost = Ghost_InitAutoGhost(this, enemyID);
int SPD = ghost->Step;
int Radius = Ghost_GetAttribute(ghost, 0, 48);//Circle radius.
int angle = Ghost_GetAttribute(ghost, 1, 0); //Starting angle.
int CCW = Ghost_GetAttribute(ghost, 2, 0);//0 - clockwise movement, 1- anti-clockwise movement, 2 - depending on Link`s positon, chosing shortest circular route.
int sizex = Ghost_GetAttribute(ghost, 3, 1);//X Size
int sizey = Ghost_GetAttribute(ghost, 4, 1);//Y size
int walkflags = Ghost_GetAttribute(ghost, 5, 0);//Add together: 1 - can phase through solid combos, 2- can move across water, 4- can move over pits.
int enemycollision = Ghost_GetAttribute(ghost, 6, 0);//>0 - collides with enemies.
ghost->Extend=3;
Ghost_SetSize(this, ghost, sizex, sizey);
Ghost_SetFlag(GHF_NORMAL);
Ghost_UnsetFlag(GHF_KNOCKBACK);
Ghost_SetFlag(GHF_NO_FALL);
int OrigTile = ghost->OriginalTile;
int State = 0;
int statecounter = 0;
int haltcounter = -1;
if ((walkflags&1)>0) Ghost_SetFlag(GHF_IGNORE_SOLIDITY);
if ((walkflags&2)>0) Ghost_SetFlag(GHF_IGNORE_WATER);
if ((walkflags&4)>0) Ghost_SetFlag(GHF_IGNORE_PITS);
int defs[18];
Ghost_StoreDefenses(ghost,defs);
int anglespeed = SPD/100;
int startangle=angle;
int origX = Ghost_X;
int origY = Ghost_Y;
Ghost_X = Ghost_X+Radius*Cos(angle);
Ghost_Y = Ghost_Y+Radius*Sin(angle);
int CollX = 0;
int CollY = 0;
if (CCW)anglespeed*=-1;
int dist=0;
while(true){
angle+=anglespeed;
Ghost_X = origX+Radius*Cos(angle);
Ghost_Y = origY+Radius*Sin(angle);
if (anglespeed<0){
CollX = CenterX(ghost)+sizex*8*Cos(angle-90);
CollY = CenterY(ghost)+sizey*8*Sin(angle-90);
}
else{
CollX = CenterX(ghost)+sizex*8*Cos(angle+90);
CollY = CenterY(ghost)+sizey*8*Sin(angle+90);
}
if (!Ghost_CanMovePixel(CollX, CollY)){
Game->PlaySound(SFX_CCIRCULUM_TRAP_BOUNCE);
anglespeed*=-1;
}
for (int i=1;i<=Screen->NumNPCs();i++){
if (enemycollision==0)break;
npc n = Screen->LoadNPC(i);
if (n==ghost)continue;
dist = Distance(CenterX(ghost), CenterY(ghost), CenterX(n), CenterY(n));
if (dist<=Min(sizex,sizey)+Min(n->TileWidth, n->TileHeight)){
Game->PlaySound(SFX_CCIRCULUM_TRAP_BOUNCE);
anglespeed*=-1;
}
}
if (angle>360)angle-=360;
if (angle<0) angle+=360;
Ghost_Waitframe(this, ghost);
}
}
}