Copy to Clipboard Test

Mobile Line of Sight Sentry (Guard) Code

///////////////////////////
/// 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