Jump to content

Photo

Script Request: Proximity FFC


  • Please log in to reply
12 replies to this topic

#1 TheLegend_njf

TheLegend_njf

    Deified

  • Members
  • Real Name:Grant

Posted 09 May 2019 - 06:26 AM

Looking for an FFC that appears based on Link's proximity to the FFC. I want to use this to make speech bubbles appear over NPCs that may have something important to say, I'd want the proximity value to be adjustable for testing purposes. 

 

Details:

  • ZC 2.50.2
  • Adjustable proximity.
  • Preferred proximity is at least 2 or 3 combos away from the NPC.
  • Would also be very nice that if a sfx is also played as well to grab players attention. 
  • If you have any other questions, please ask. 
  • In case anybody is wondering, I've added script request to the title of this topic mainly so people can tell what it is by looking at the forum sidebar.


#2 Emily

Emily

    Scripter / Dev

  • ZC Developers

Posted 09 May 2019 - 09:45 AM

I think the 'Tango.zh' demo has something like that...

#3 ywkls

ywkls

    Master

  • Members

Posted 09 May 2019 - 04:05 PM

I created something like this for my quest's signs.

It really feels to me like it would be something that was better included in the NPC script, rather than separate.

Anyways, here's a version of the script that should be what you want.

const int THINK_COMBO= 0;//Combo number to display as an indicator.
const int THINK_CSET = 0;//CSet of combo displayed.

// FFC script for NPC's that notice you
// d0: String number to be displayed
// d1: How far away to display indicator
// d2: Sound to make when indicator shows up

ffc script Notice_NPC{
    void run(int message, int distance, int sfx){
        while(true){
            int LinkX = Link->X + 8;
	    int LinkY = Link->Y + 8;
	    int thisX = Round(this->X / 8) * 8;
	    int thisY = Round(this->Y / 8) * 8;	
	    int centerX = thisX + this->EffectWidth / 2;
	    int centerY = thisY + this->EffectHeight / 2;
	    // If Link is on one of the sides of the NPC and facing it
	    if( 
		((Abs(LinkX - centerX) < distance 
                && Abs(LinkY - centerY) <= distance
                && LinkY < centerY && Link->Dir == DIR_DOWN) ||
		(Abs(LinkX - centerX) < distance
                 && Abs(LinkY - centerY) <= distance
                 && LinkY > centerY && Link->Dir == DIR_UP) ||
		(Abs(LinkY + 3 - centerY) < distance
                 && Abs(LinkX - centerX) <= distance
                 && LinkX < centerX && Link->Dir == DIR_RIGHT) ||
		(Abs(LinkY + 3- centerY) < distance
                 && Abs(LinkX - centerX) <= distance
                 && LinkX > centerX && Link->Dir == DIR_LEFT))){
                    //This version makes the indicator appear above Link.
		    Screen->FastCombo(4,Link->X,Link->Y-16,THINK_COMBO,THINK_CSET,128);
                    //This one makes it appear above the ffc
                    //Screen->FastCombo(4,this->X,this->Y-16,THINK_COMBO,THINK_CSET,128);
                    //This would play every frame with this configuration.
                    //To have a timed sfx would require a slightly different set up.
                    //However I'm not sure which you'd want.
                    Game->PlaySound(sfx);
                    // If the player presses the button to talks
                    //Change this if using a different button
		     if(Link->PressEx1){
                    // Show the message
			Link->InputEx1 = false;
                        Screen->Message(message);
                     } // End of if Link triggered sign
            }
	    Waitframe();   
        } 
    } 
} 

Let me know if you have any questions.


  • ShadowTiger likes this

#4 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 10 May 2019 - 01:35 PM

I created something like this for my quest's signs.
It really feels to me like it would be something that was better included in the NPC script, rather than separate.
Anyways, here's a version of the script that should be what you want.

const int THINK_COMBO= 0;//Combo number to display as an indicator.
const int THINK_CSET = 0;//CSet of combo displayed.

// FFC script for NPC's that notice you
// d0: String number to be displayed
// d1: How far away to display indicator
// d2: Sound to make when indicator shows up

ffc script Notice_NPC{
    void run(int message, int distance, int sfx){
        while(true){
            int LinkX = Link->X + 8;
	    int LinkY = Link->Y + 8;
	    int thisX = Round(this->X / 8) * 8;
	    int thisY = Round(this->Y / 8) * 8;	
	    int centerX = thisX + this->EffectWidth / 2;
	    int centerY = thisY + this->EffectHeight / 2;
	    // If Link is on one of the sides of the NPC and facing it
	    if( 
		((Abs(LinkX - centerX) < distance 
                && Abs(LinkY - centerY) <= distance
                && LinkY < centerY && Link->Dir == DIR_DOWN) ||
		(Abs(LinkX - centerX) < distance
                 && Abs(LinkY - centerY) <= distance
                 && LinkY > centerY && Link->Dir == DIR_UP) ||
		(Abs(LinkY + 3 - centerY) < distance
                 && Abs(LinkX - centerX) <= distance
                 && LinkX < centerX && Link->Dir == DIR_RIGHT) ||
		(Abs(LinkY + 3- centerY) < distance
                 && Abs(LinkX - centerX) <= distance
                 && LinkX > centerX && Link->Dir == DIR_LEFT))){
                    //This version makes the indicator appear above Link.
		    Screen->FastCombo(4,Link->X,Link->Y-16,THINK_COMBO,THINK_CSET,128);
                    //This one makes it appear above the ffc
                    //Screen->FastCombo(4,this->X,this->Y-16,THINK_COMBO,THINK_CSET,128);
                    //This would play every frame with this configuration.
                    //To have a timed sfx would require a slightly different set up.
                    //However I'm not sure which you'd want.
                    Game->PlaySound(sfx);
                    // If the player presses the button to talks
                    //Change this if using a different button
		     if(Link->PressEx1){
                    // Show the message
			Link->InputEx1 = false;
                        Screen->Message(message);
                     } // End of if Link triggered sign
            }
	    Waitframe();   
        } 
    } 
} 
Let me know if you have any questions.


That is a lot of extra work...

std.zh noww has Below(ffc) ad DistX)FFC), DistY(ffc). Ise thosse.

#5 TheLegend_njf

TheLegend_njf

    Deified

  • Members
  • Real Name:Grant

Posted 16 May 2019 - 07:30 AM

Where I don't script, I can't really edit the current NPC script. The main reason I still make NPC scripts is to take a lot of burden off the current people who are making scripts for me. While I do agree with you, this is a very specific situation that I need for one instance in my quest where a lot of NPCs do not talk to link in this one particular area, so having players be able to tell the difference between a talking NPC and a non talking NPC is important for this area. It's not something that I feel where I need to overhaul the current NPC script for at the moment.

 

I'll use your script right away. 



#6 TheLegend_njf

TheLegend_njf

    Deified

  • Members
  • Real Name:Grant

Posted 16 May 2019 - 11:44 AM

So this script doesn't work right at all, so I should have elaborated:

  • The script puts the icon above Link, but I'd prefer to have the icon appear above the NPC.
  • The sfx plays when you leave the proximity, not enter it... I'm pretty sure this was not intentional. 


#7 ywkls

ywkls

    Master

  • Members

Posted 16 May 2019 - 12:31 PM

 

So this script doesn't work right at all, so I should have elaborated:

  • The script puts the icon above Link, but I'd prefer to have the icon appear above the NPC.
  • The sfx plays when you leave the proximity, not enter it... I'm pretty sure this was not intentional. 

 

 

Is the icon for interacting with it appearing at the right time? If that's so, I think I know why the sound isn't playing correctly.

Because it is trying to play the sound every frame, you only hear it on the frame when it stops trying to play the sound.

const int THINK_COMBO= 0;//Combo number to display as an indicator.
const int THINK_CSET = 0;//CSet of combo displayed.

// FFC script for NPC's that notice you
// d0: String number to be displayed
// d1: How far away to display indicator
// d2: Sound to make when indicator shows up
// d3: How often to play sound.

ffc script Notice_NPC{
    void run(int message, int distance, int sfx, int sfx_time){
        int sfx_plays;
		while(true){
            int LinkX = Link->X + 8;
	    int LinkY = Link->Y + 8;
	    int thisX = Round(this->X / 8) * 8;
	    int thisY = Round(this->Y / 8) * 8;	
	    int centerX = thisX + this->EffectWidth / 2;
	    int centerY = thisY + this->EffectHeight / 2;
	    // If Link is on one of the sides of the NPC and facing it
	    if( 
		((Abs(LinkX - centerX) < distance 
                && Abs(LinkY - centerY) <= distance
                && LinkY < centerY && Link->Dir == DIR_DOWN) ||
		(Abs(LinkX - centerX) < distance
                 && Abs(LinkY - centerY) <= distance
                 && LinkY > centerY && Link->Dir == DIR_UP) ||
		(Abs(LinkY + 3 - centerY) < distance
                 && Abs(LinkX - centerX) <= distance
                 && LinkX < centerX && Link->Dir == DIR_RIGHT) ||
		(Abs(LinkY + 3- centerY) < distance
                 && Abs(LinkX - centerX) <= distance
                 && LinkX > centerX && Link->Dir == DIR_LEFT))){
                    Screen->FastCombo(4,this->X,this->Y-16,THINK_COMBO,THINK_CSET,128);
                    sfx_plays= TimedSFx(sfx_plays,sfx,sfx_time);
                    // If the player presses the button to talks
                    //Change this if using a different button
		     if(Link->PressEx1){
                    // Show the message
			Link->InputEx1 = false;
                        Screen->Message(message);
                     } // End of if Link triggered sign
            }
	    Waitframe();   
        } 
    } 
} 

//Moosh code. Use at your own peril. :)
int TimedSFX(int timer, int sfx, int freq){
	timer++;
	if(timer>=freq){
		Game->PlaySound(sfx);
		timer = 0;
	}
	return timer;
}

This should fix those problems, but let me know if it doesn't.



#8 TheLegend_njf

TheLegend_njf

    Deified

  • Members
  • Real Name:Grant

Posted 16 May 2019 - 04:57 PM

Timedsfx is undeclared.

 

Update: I see it now, for some reason I didn't copy paste it, but also your warning concerns me, I should bring it up to Moosh. 

 

Update again: Nevermind, that was a joke. My brain is not with it at the moment. 

 

Update yet again: It does seem like I copy pasted it, but there was a small error you left in there. I just fixed it. 



#9 TheLegend_njf

TheLegend_njf

    Deified

  • Members
  • Real Name:Grant

Posted 16 May 2019 - 07:12 PM

Icon doesn't appear at all now, perhaps I should show you an image of what I'm looking for, but I'll have to do it on discord because of spoilers. 



#10 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 17 May 2019 - 02:37 PM

Icon doesn't appear at all now, perhaps I should show you an image of what I'm looking for, but I'll have to do it on discord because of spoilers.


It sounds as if you are trying to add this on top of an existing npc disalogue script.

If so, then post whatever script that you are using to control the npc itself. It's a simple matter to add this direct to that script, rather than to tack on more, and more scripts to acomplish it.

Literally < 6 lines.
 
Here is a completely new script, too.
 
const int TalkingTime___TALKBUTTON_A = 0;
const int TalkingTime___TALKBUTTON_B = 0;
const int TalkingTime___TALKBUTTON_L = 0;
const int TalkingTime___TALKBUTTON_R = 0;
const int TalkingTime___TALKBUTTON_EX1 = 0;
const int TalkingTime___TALKBUTTON_EX2 = 0;
const int TalkingTime___TALKBUTTON_EX3 = 0;
const int TalkingTime___TALKBUTTON_EX4 = 0;

const int TalkingTime_Icon_Offset_X = 18;
const int TalkingTime_Icon_Offset_Y = -18;

ffc script TalkingTime
{
	void run(int m, int distx, int disty, bool only_below, int icon_tile, int icon_cset, int sfx, int sfx_delay)
	{
		int clk = -1; bool played_sfx;
		while(1)
		{
			if ( clk > 1 ) { --clk; }
			else if ( !clk && !played_sfx )
			{
				clk = -1;
				played_sfx = true;
				Game->PlaySound(sfx);
			}
			if ( Facing(this) )
			{
				if ( (only_below && Below(this)) || !only_below )
				{
					if ( DistX(this,distx) )
					{
						if ( DistY(this,disty) )
						{
							//Draw the icon
							Screen->FastTile(6, this->X+TalkingTime_Icon_Offset_X, this->Y+TalkingTime_Icon_Offset_Y, icon_tile, icon_cset, OP_OPAQUE);
							clk = sfx_delay;
							if ( ___TalkPressed() )
							{
								Screen->Message(m);
							}
						}
					}
				}
			}
			
			Waitframe();
		}
		
	}
	bool ___TalkPressed()
	{
		if ( TalkingTime___TALKBUTTON_A && Link->PressA ) return true;
		if ( TalkingTime___TALKBUTTON_B && Link->PressB ) return true;
		if ( TalkingTime___TALKBUTTON_L && Link->PressL ) return true;
		if ( TalkingTime___TALKBUTTON_R && Link->PressR ) return true;
		if ( TalkingTime___TALKBUTTON_EX1 && Link->PressEx1 ) return true;
		if ( TalkingTime___TALKBUTTON_EX2 && Link->PressEx2 ) return true;
		if ( TalkingTime___TALKBUTTON_EX3 && Link->PressEx3 ) return true;
		if ( TalkingTime___TALKBUTTON_EX4 && Link->PressEx4 ) return true;
		return false;
	}
	
}
 
That should do it. Requires the std.zh from 2.53.0 and above.

#11 xenomicx

xenomicx

    Zelda Arcade

  • Members
  • Location:Chi-town

Posted 09 September 2019 - 04:46 PM

I created something like this for my quest's signs.

It really feels to me like it would be something that was better included in the NPC script, rather than separate.

Anyways, here's a version of the script that should be what you want.

const int THINK_COMBO= 0;//Combo number to display as an indicator.
const int THINK_CSET = 0;//CSet of combo displayed.

// FFC script for NPC's that notice you
// d0: String number to be displayed
// d1: How far away to display indicator
// d2: Sound to make when indicator shows up

ffc script Notice_NPC{
    void run(int message, int distance, int sfx){
        while(true){
            int LinkX = Link->X + 8;
	    int LinkY = Link->Y + 8;
	    int thisX = Round(this->X / 8) * 8;
	    int thisY = Round(this->Y / 8) * 8;	
	    int centerX = thisX + this->EffectWidth / 2;
	    int centerY = thisY + this->EffectHeight / 2;
	    // If Link is on one of the sides of the NPC and facing it
	    if( 
		((Abs(LinkX - centerX) < distance 
                && Abs(LinkY - centerY) <= distance
                && LinkY < centerY && Link->Dir == DIR_DOWN) ||
		(Abs(LinkX - centerX) < distance
                 && Abs(LinkY - centerY) <= distance
                 && LinkY > centerY && Link->Dir == DIR_UP) ||
		(Abs(LinkY + 3 - centerY) < distance
                 && Abs(LinkX - centerX) <= distance
                 && LinkX < centerX && Link->Dir == DIR_RIGHT) ||
		(Abs(LinkY + 3- centerY) < distance
                 && Abs(LinkX - centerX) <= distance
                 && LinkX > centerX && Link->Dir == DIR_LEFT))){
                    //This version makes the indicator appear above Link.
		    Screen->FastCombo(4,Link->X,Link->Y-16,THINK_COMBO,THINK_CSET,128);
                    //This one makes it appear above the ffc
                    //Screen->FastCombo(4,this->X,this->Y-16,THINK_COMBO,THINK_CSET,128);
                    //This would play every frame with this configuration.
                    //To have a timed sfx would require a slightly different set up.
                    //However I'm not sure which you'd want.
                    Game->PlaySound(sfx);
                    // If the player presses the button to talks
                    //Change this if using a different button
		     if(Link->PressEx1){
                    // Show the message
			Link->InputEx1 = false;
                        Screen->Message(message);
                     } // End of if Link triggered sign
            }
	    Waitframe();   
        } 
    } 
} 

Let me know if you have any questions.

So I'm wondering if this is the same math I could use for a landmine type enemy. Been trying to figure one out for a week now that can only be seen with the lense of truth.



#12 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 10 September 2019 - 02:25 AM

So I'm wondering if this is the same math I could use for a landmine type enemy. Been trying to figure one out for a week now that can only be seen with the lense of truth.


Version? It'd be very easy with npc scripts. I already have an npc script to explode on contact, so proximity would be very similar.

If not 2.55, then it depends how you want to approach it with regard to script handling.

You should look at DistX, DistY, DistXY, LinkFacing, and related functions in std.zh in either 2.53, or 2.55.

If you aren't using 2.55, then you have far, far too many logical ANDs there. That one statement chain will check absolutely every one of those conditions every frame, even if any fail to evaluate true.

2.55 fixes this, but in earlier versions, I advise using nested if statements instead of logical AND.

You a bunch of ints there trying to optimise by avoiding redundant maths, so it appears that you want to optimise, but the very long && chain is basically negating that attempt.

Look at the signpost in Classic.zh. It's highly optimised:

ffc script SignPost
{
	void run(int m, int max_dist)
	{
		this->Data = CMB_INVISIBLE;
		if ( max_dist < 1 ) max_dist = _classic_zh__SIGNPOST_DIST;
		while(1)
		{
			if ( Below(this) )
			{
				if ( Facing(this) )
				{
					if ( DistXY(this, max_dist) )
					{
						if ( Link->PressA || Link->PressB )
						{
							Screen->Message(m);
						}
					}
				}
			}
			Waitframe();
		}
	}
}


#13 ywkls

ywkls

    Master

  • Members

Posted 10 September 2019 - 10:05 AM

Whenever I did a scripted lens, I had the enemy draw itself based on data stored ahead of time.
 

const int LENS_FFC_SCRIPT = 27;

//Scripted Lens Constants

const int INVISIBLE_MISC_INDEX = 0;//Used by scripted lens. Stores combo to draw.
const int DRAWN_MISC_INDEX = 1;//Used by scripted lens. Tells whether or not to draw enemy.
const int LENS_RADIUS = 60;//Width of scripted lens aperture.

item script LensReveal{
	void run(int dummy, int LensCost){
		if(Link->MP>=LensCost){
			int args[8]={LensCost};
			RunFFCScript(LENS_FFC_SCRIPT,args);
		}
	}
}

ffc script Lens_Shows_Enemies{
	void run(int LensCost){
		npc ghost;
		int i;
		while(Link->PressB ||Link->InputB){
			if(Link->MP<LensCost)
				break;
			for(i=1;i<=Screen->NumNPCs();i++){
				ghost = Screen->LoadNPC(i);
				if(ghost->Defense[NPCD_BYRNA]==NPCDT_ONEHITKILL)
					ghost->Misc[DRAWN_MISC_INDEX]= 1;	
			}
			Waitframe();
		}
		ghost->Misc[DRAWN_MISC_INDEX]= 0;
		this->Data = 0;
		Quit();
	}
}

//Draw an inverted circle (fill whole screen except circle)
//Also draws an enemy if it is invisible and ghosted.
void InvertedLensCircle(int bitmapID, int layer, int x, int y, int radius, int scale, int fillcolor,npc ghost){
    Screen->SetRenderTarget(bitmapID);     //Set the render target to the bitmap.
    Screen->Rectangle(layer, 0, 0, 256, 176, fillcolor, 1, 0, 0, 0, true, 128); //Cover the screen
	Screen->Circle(layer, x, y, radius, 0, scale, 0, 0, 0, true, 128); //Draw a transparent circle.
    if(ghost->Dir==DIR_UP||ghost->Dir==DIR_LEFTUP)Screen->DrawCombo(layer, ghost->X, ghost->Y, ghost->Misc[INVISIBLE_MISC_INDEX], ghost->TileWidth, ghost->TileHeight, ghost->Attributes[8], -1, -1, 0, 0, 0, -1, 0, true, OP_OPAQUE);
	else if(ghost->Dir==DIR_DOWN ||ghost->Dir== DIR_RIGHTDOWN)Screen->DrawCombo(layer, ghost->X, ghost->Y, ghost->Misc[INVISIBLE_MISC_INDEX]+1, ghost->TileWidth, ghost->TileHeight, ghost->Attributes[8], -1, -1, 0, 0, 0, -1, 0, true, OP_OPAQUE);
	else if(ghost->Dir==DIR_LEFT||ghost->Dir== DIR_LEFTDOWN)Screen->DrawCombo(layer, ghost->X, ghost->Y, ghost->Misc[INVISIBLE_MISC_INDEX]+2, ghost->TileWidth, ghost->TileHeight, ghost->Attributes[8], -1, -1, 0, 0, 0, -1, 0, true, OP_OPAQUE);
	else if(ghost->Dir==DIR_RIGHT||ghost->Dir== DIR_RIGHTUP)Screen->DrawCombo(layer, ghost->X, ghost->Y, ghost->Misc[INVISIBLE_MISC_INDEX]+3, ghost->TileWidth, ghost->TileHeight, ghost->Attributes[8], -1, -1, 0, 0, 0, -1, 0, true, OP_OPAQUE);
	Screen->SetRenderTarget(RT_SCREEN); //Set the render target back to the screen.
    Screen->DrawBitmap(layer, bitmapID, 0, 0, 256, 176, 0, 0, 256, 176, 0, true); //Draw the bitmap
}

//Draws scripted enemies with scripted lens.

void Drawn_Enemy_Waitframe(ffc this, npc ghost){
	if(Ghost_Waitframe(this,ghost,false,false)){
		if(ghost->Misc[DRAWN_MISC_INDEX]==1)InvertedLensCircle(4, 6, CenterLinkX(), CenterLinkY(), LENS_RADIUS, 1, 15,ghost);
	}
	else if(!Ghost_Waitframe(this, ghost, false, false)){
	   Ghost_DeathAnimation(this, ghost, 2);
	   Quit();
    }
}

While this won't handle the explosion part; the other code that's been posted here should help with that.


Edited by ywkls, 10 September 2019 - 10:07 AM.



0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users