/////////////////////////// /// Moving Sentinel FFC /// /// v0.4.4 /// /// 12th october, 2017 /// /// By: ZoriaRPG /// ///////////////////////////////////////////////////////////////////////////// /// A mobile sentry that halts Link when it sees him, and warps him away. /// /// Set this to an ffc with an invisible combo (usually combo 1) /// /// that moves along a path of changers. /// ///////////////////////////////////////////////////////////////////////////// /// D0: Sound effect. /// D1: String /// D2: Destination DMap /// D3: Destination Screen /// D4: NPC to use (for display purposes) /// D5: Initial facing direction, where 0 == UP, 1 == DOWN, 2 == LEFT, 3 == RIGHT const int FFC_SENTINEL_SOUND_DELAY = 50; //Delay between sound and string. const int FFC_SENTINEL_MESSAGE_WARP_DELAY = 60; //Delay between string, and warp. const int FFC_SENTINEL_SFX_WHISTLE = 63; //Default sound. const int FFC_SENTINEL_DEFAULT_STRING = 1; //Default string. const int FFC_SENTINEL_SPR_BLANK = 88; //A blank weapon sprite. const int FFC_SENTINEL_LOS_GUARD_PRECISION = 7; const int FFC_SENTINEL_LOS_WEAPON_PRECISION = 14; ffc script MovingSentinel { void run(int sfx, int str, int dmap, int scrn, int npcid, int init_dir) { int q[2]; npc n = Screen->CreateNPC(npcid); //Used to visibly display the sentry using a sprite. n->HitWidth = 0; n->HitYOffset = -32768; //THe NPC has no collision rect. n->X = this->X; n->Y = this->Y; //Lock the NPC coordinates to the FFC. eweapon spotter; //Used to check for solidity in LoS. int numew; bool spotted; int delay; int spotcond; bool hit; if ( init_dir < 0 || init_dir > 3 ) init_dir = DIR_DOWN; //Face down by default. int dir = init_dir; //FFCs have no 'dir' variable, so we need to give this a direction. n->Dir = dir; //Lock the NPC to the same dir as this. bool spawnedweapon; //Sanity checks. if ( sfx < 1 ) sfx = FFC_SENTINEL_SFX_WHISTLE; //Default if ( str < 1 ) str = FFC_SENTINEL_DEFAULT_STRING; //begin infinite loop while(1) { if ( Link->Invisible ) { continue; } //Generate the physical weapon if Link is in LoS of the ffc //to determine if that LoS should be blocked! if ( spotted ) { //int ssd2[]="Spotted!"; TraceS(ssd2); if ( !spawnedweapon ) { spawnedweapon = true; //fire LoS Weapon spotter = Screen->CreateEWeapon(EW_ARROW); //Generate a weapon with properties that we can use. spotter->HitYOffset = -32768; //Move the collision rect off-screen. spotter->UseSprite(FFC_SENTINEL_SPR_BLANK); //invisible spotter->X = this->X; //Spawn from the FFC->X/Y. spotter->Y = this->Y; spotter->HitWidth = 16; //May be useful for Collision using the actual weapon size. spotter->HitHeight = 16; spotter->Dir = dir; //Aim in the direction of the ffc. spotter->Step = 1600; //Mad-fast for instant-hit. //1600 is one tile per frame. This means that the farther away Link stands, from // a LoS check, the more 'grace' he has in avoiding being seen. //16000 would be ten tiles per frame. //25600 would be the screen width in one frame. } } //A way to ensure that LoS is blocked by any solid object. //Uses an eweapon that is destroyed when it hits a solid object. //If it hits Link, he is spotted. if ( spotter->isValid() ) { //If the weapon hits a solid space, remove it. if ( Screen->isSolid(spotter->X, spotter->Y) ) { Remove(spotter); spawnedweapon = false; } //If it collides with Link, remove it, and begin the process of removing him, too. if ( FFC_Sentinel_DistXY(spotter, FFC_SENTINEL_LOS_WEAPON_PRECISION) ) { Remove(spotter); hit = true; } } else spawnedweapon = false; //If Link is hit with the LoS projectile: if ( hit ) { for ( q[0] = Screen->NumNPCs(); q[0] > 0; q[0]-- ) { n = Screen->LoadNPC(q[0]); n->Stun = 214747; //Stun all of the npcs on the screen so that they do not wander. } for ( q[1] = Screen->NumEWeapons(); q[1] > 0; q[1]-- ) { spotter = Screen->LoadEWeapon(q[1]); spotter->HitYOffset = -32768; //Move all weapon collision boxes offscreen so that they cannot harm Link. } //Condition 0, Play the sound. if ( spotcond == 0 ) { delay = FFC_SENTINEL_SOUND_DELAY; //Set the timer. NoAction(); //Freeze Link. Game->PlaySound(sfx); //Play the sound. for ( ; delay > 0; delay-- ) { WaitNoAction(); //Wait for the duration of the timer. } spotcond = 1; //Advance to condition 1. Waitframe(); } //Condition 1, show the message. if ( spotcond == 1 ) { delay = FFC_SENTINEL_MESSAGE_WARP_DELAY; //Set the timer. NoAction(); //Freeze Link Screen->Message(str); //Show the string. for ( ; delay > 0; delay-- ) { WaitNoAction(); //Wait for the duration of the timer. } spotcond = 2; //Advance to condition 2. Waitframe(); } //Condition 2, warp. if ( spotcond == 2 ) { Link->Warp(dmap,scrn); //Warp Link tot he desired coordinates. //! This will use Warp Return A on the destination screen. //! This will also automatically exit the ffc script. } Waitframe(); //Emergency waitframe call. } //end (hit) loop //Establish the ffc facing direction. if ( this->Vy < 0 ) { dir = DIR_UP; //The ffc is moving upward. } else if ( this->Vy > 0 ) { dir = DIR_DOWN; //The ffc is moving downward. } else if ( this->Vx > 0 ) { dir = DIR_RIGHT; //The ffc is moving right. } else if ( this->Vx < 0 ) { dir = DIR_LEFT; //The ffc is moving left. //This was DIR_RIGHT!!! Last block effect in action. -Z } else { dir = init_dir; //The ffc is NOT moving, so use the static dir. } n->Dir = dir; //Lock the NPC to the same dir as this. n->X = this->X; n->Y = this->Y; //Move the npc with this. if ( !spotted ) { //Check for LoS: if ( dir == DIR_LEFT ) { //if Link is to the left of the sentinel if ( FFC_Sentinel_LinkLeftOf(this) ) { //and within 8 pixels of the sentinel's Y axis if ( FFC_Sentinel_DistY(this, FFC_SENTINEL_LOS_GUARD_PRECISION) ) { spotted = true; //we see you. continue; //resume loop from the top. } } } if ( dir == DIR_RIGHT ) { //if Link is to the left of the sentinel if ( FFC_Sentinel_LinkRightOf(this) ) { //and within 8 pixels of the sentinel's Y axis if ( FFC_Sentinel_DistY(this, FFC_SENTINEL_LOS_GUARD_PRECISION) ) { spotted = true; continue; } } } if ( dir == DIR_UP ) { //if Link is to the left of the sentinel if ( FFC_Sentinel_LinkAbove(this) ) { //and within 8 pixels of the sentinel's X axis if ( FFC_Sentinel_DistX(this, FFC_SENTINEL_LOS_GUARD_PRECISION) ) { spotted = true; continue; } } } if ( dir == DIR_DOWN ) { //if Link is to the left of the sentinel if ( FFC_Sentinel_LinkBelow(this) ) { //and within 8 pixels of the sentinel's X axis if ( FFC_Sentinel_DistX(this, FFC_SENTINEL_LOS_GUARD_PRECISION) ) { spotted = true; continue; } } } //end LoS checks. } Waitframe(); } //end infinite loop. } //end run() //! Local functions //These are copies of functions from std.zh 2.0, with renamed //identifiers, set at a scope local to this script. bool FFC_Sentinel_DistX(ffc a, int distance) { int dist; if ( a->X > Link->X ) dist = a->X - Link->X; else dist = Link->X - a->X; return ( dist <= distance ); } bool FFC_Sentinel_DistY(ffc a, int distance) { int dist; if ( a->Y > Link->Y ) dist = a->Y - Link->Y; else dist = Link->Y - a->Y; return ( dist <= distance ); } bool FFC_Sentinel_LinkAbove(ffc n){ return Link->Y < n->Y; } bool FFC_Sentinel_LinkBelow(ffc n){ return Link->Y > n->Y; } bool FFC_Sentinel_LinkLeftOf(ffc n){ return Link->X < n->X; } bool FFC_Sentinel_LinkRightOf(ffc n){ return Link->X > n->X; } bool FFC_Sentinel_DistXY(eweapon b, int distance) { int distx; int disty; if ( Link->X > b->X ) distx = Link->X - b->X; else distx = b->X - Link->X; if ( Link->Y > b->Y ) disty = Link->Y - b->Y; else disty = b->Y - Link->Y; return ( distx <= distance && disty <= distance ); } } //end script