Jump to content

Photo

I am really having trouble with combining Global Scripts

Help Combining Global Question Global Script Combining Global Scripts

  • Please log in to reply
8 replies to this topic

#1 SparksTheUnicorn

SparksTheUnicorn

    Lonk, Hero of Lime

  • Members

Posted 11 May 2020 - 10:42 AM

So I am relatively new to Zelda Classic, but I am loving it so far. Recently, I have started to try implementing scripts into my quest, and have now come upon the problem of needing to combine multiple global scripts. The issue, however, is that I seem to really suck at doing so. No matter what I do it never seems to work. I tried following the tutorial but it just confused me and didn't seem to help as the program still couldn't compile it. I even tried using Moosh's global script combiner and that didn't work either. As someone who really doesn't understand scripting, I just don't really know how to figure out what I am doing wrong here, and honestly any help at all would be greatly appreciated. I am using the most recent download provided on the Zelda Classic website for 2.55 (I believe it is Alpha 70 but I may be wrong, sorry), and if it helps the scripts I am having issues with are Moosh's Pit Script, venrob's Crystal Switch script, and MoscowModder's Simplified GBShield script.


Edited by SparksTheUnicron, 11 May 2020 - 10:44 AM.


#2 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 11 May 2020 - 12:26 PM

Okay, let's walk through this then. I can combine these easily enough, but I also wanna try explaining why I'm doing what I'm doing to help with combining stuff in the future.

So a global script basically has two main parts. When the game starts, the global script does anything that needs to happen right at the beginning of the game. For example, if your red/blue blocks are supposed to restart when you game over, then the global script will reset them on that first split second the game starts. After that, it enters a big loop. Everything inside that loop will run every frame. So anything that needs to run every frame must go inside that loop. The actual structure of the script looks like this:
 

global script slot2{
	void run(){
		//Everything that runs at the start of the game goes right here
		while(true){
			//Everything that runs every frame of the game goes here
			Waitframe();
		}
	}
}

Another thing that's often done with global scripts is to use functions to make it easier to read. For example, let's say I have a global script that... I dunno, sets Link's HP and MP to max every frame and also just gives him money. Why would I want that? I dunno. But let's pretend I did. It might look something like this:
 

global script slot2{
	void run(){
		while(true){
			Link->HP = Link->MaxHP;
			Link->MP = Link->MaxMP;
			Game->Counter[CR_RUPEES] += 1;
			Waitframe();
		}
	}
}

This is still a fairly simple global script. But you can start the see the issue. If I combine multiple scripts together, it might be hard to tell where one ends and the next begins. We can get around this by using functions.
 

void Russ_HpMpRupeeFunction(){
	Link->HP = Link->MaxHP;
	Link->MP = Link->MaxMP;
	Game->Counter[CR_RUPEES] += 1;
}

global script slot2{
	void run(){
		while(true){
			Russ_HpMpRupeeFunction();
			Waitframe();
		}
	}
}

Now in the global script, it's super clear and organized. Everything is still happening, but each individual script is organized into one single line, making it easy to tell what's actually running in the global script.

If you look at Moosh's pit script, you'll notice he already does this:
 

global script MooshPitGlobal{
	void run(){
		MooshPit_Init();
		while(true){
			MooshPit_Update();
			Waitframe();
		}
	}
}

There's a heck of a lot of code in Moosh's script, but because it's organized, it can be SUPER easily combined with other scripts. Unfortunately, the other two are slightly messier, but we can still make this work. When combining global scripts, there's only two things you need to do.

1. Everything between void run() and while(true){ in the separate scripts needs to be copy/pasted to that spot in your global script.
2. Everything between while(true){ and Waitframe(); needs to be copied to that spot in your global script.

There's likely a lot of other functions included in the script. But if they're not inside something labeled global script, don't worry about them! Copy paste them into your script file, but you don't need to merge anything with them. Now then, let's try this out with the three scripts you linked:
 

global script slot2{
	void run(){
		//Everything that runs at the start of the game goes right here
		//First, Moosh's pit script
		MooshPit_Init();
		
		//Next, Rob's red/blue blocks
		int lastScreen = Game->GetCurScreen();
        int lastMap = Game->GetCurMap();
        int lastLevel = Game->GetCurLevel();
		
		//Finally, MoscowModder's GB Shield
		bool shieldOn;
		while(true){
			//Everything that runs every frame of the game goes here
			//First, Moosh's pit script
			MooshPit_Update();
			
			//Next, Rob's red/blue blocks
			if(Game->GetCurScreen() != lastScreen || Game->GetCurMap() != lastMap || Game->GetCurLevel() != lastLevel)
			{
                lastScreen = Game->GetCurScreen();
                lastMap = Game->GetCurMap();
                lastLevel = Game->GetCurLevel();
                checkSwitchCombos(true);
            }
			if(CAN_WALK_ON_TOP)checkLinkOnRaised();
			
			//Finally, MoscowModder's GB Shield
			if( !shieldOn && shieldItem ){ //Enable shield when using dummy
				shieldOn=true; //Set shield state to on
				Link->Item[shieldItem]=true; //Give the shield
				Game->PlaySound(SFX_GBSHIELD); //Play the sound
			}
			else if( ( (shieldButton && !Link->InputA)||(!shieldButton && !Link->InputB)) //When button is released
					&& shieldOn){ //And shield is still on
				Link->Item[shieldItem]=false; //Remove shield
				shieldItem = 0; //Reset shield item variable
				shieldOn = false; //Set shield state to off
			}
			Waitframe();
		}
	}
}

And there we have it. All the scripts have been combined. Remember, there's a lot of other functions and constants included in those scripts, and all of those must be included in your script file. But as far as actually combining the global scripts, this is all it takes. One last point to make: Rob's script also has something called global script Init. And Init script is a special kind of global script that runs as soon as the game starts the first time. That global script doesn't need to be combined with the main script; we can just load it into slot 1 in the global scripts tab. If you need to combine multiple init scripts, it's similar to this; just copy paste everything between void run(){ and } in the various init scripts.

One last thing while we're here. This isn't necessary to do, so if you're confused, you can just stop reading at this point. You have a combined global script. But, if we wanted to make things easier to read, we could condense things into functions. Remember how I showed how my global script could all be put into a single line function, to make it easier to read? And how Moosh did that with his? We can do the same thing with Rob's and MoscowModder's scripts here too.
 

global script slot2{
	void run(){
		//Everything that runs at the start of the game goes right here
		//First, Moosh's pit script
		MooshPit_Init();
		
		//Next, Rob's red/blue blocks
		int lastScreen = Game->GetCurScreen();
		int lastMap = Game->GetCurMap();
		int lastLevel = Game->GetCurLevel();
		
		//Finally, MoscowModder's GB Shield
		bool shieldOn;
		while(true){
			//Everything that runs every frame of the game goes here
			//First, Moosh's pit script
			MooshPit_Update();
			
			//Next, Rob's red/blue blocks
			RobBlock_Update();
			
			//Finally, MoscowModder's GB Shield
			GBShield_Update();
			Waitframe();
		}
	}
}

void RobBlock_Update(){
	if(Game->GetCurScreen() != lastScreen || Game->GetCurMap() != lastMap || Game->GetCurLevel() != lastLevel)
	{
		lastScreen = Game->GetCurScreen();
		lastMap = Game->GetCurMap();
		lastLevel = Game->GetCurLevel();
		checkSwitchCombos(true);
	}
	if(CAN_WALK_ON_TOP)checkLinkOnRaised();
}

void GBShield_Update(){
	if( !shieldOn && shieldItem ){ //Enable shield when using dummy
		shieldOn=true; //Set shield state to on
		Link->Item[shieldItem]=true; //Give the shield
		Game->PlaySound(SFX_GBSHIELD); //Play the sound
	}
	else if( ( (shieldButton && !Link->InputA)||(!shieldButton && !Link->InputB)) //When button is released
			&& shieldOn){ //And shield is still on
		Link->Item[shieldItem]=false; //Remove shield
		shieldItem = 0; //Reset shield item variable
		shieldOn = false; //Set shield state to off
	}
}

Why would we do it this way? It makes it MUCH easier to read. If you're looking through the global script and want to know what's running every frame, it's pretty easy to understand:
 

		while(true){
			//Everything that runs every frame of the game goes here
			//First, Moosh's pit script
			MooshPit_Update();
			
			//Next, Rob's red/blue blocks
			RobBlock_Update();
			
			//Finally, MoscowModder's GB Shield
			GBShield_Update();
			Waitframe();
		}

If you wanted to remove a script, it'd be a one line deletion. You can name these functions whatever you want. You just have to make sure you cut and paste every part of the original, uncombined script between while(true){ and Waitframe(); into the function.

I hope all this makes sense. I'm happy to answer any questions if I've left you confused.


  • Matthew and SparksTheUnicorn like this

#3 SparksTheUnicorn

SparksTheUnicorn

    Lonk, Hero of Lime

  • Members

Posted 11 May 2020 - 03:40 PM

Okay, let's walk through this then. I can combine these easily enough, but I also wanna try explaining why I'm doing what I'm doing to help with combining stuff in the future.

So a global script basically has two main parts. When the game starts, the global script does anything that needs to happen right at the beginning of the game. For example, if your red/blue blocks are supposed to restart when you game over, then the global script will reset them on that first split second the game starts. After that, it enters a big loop. Everything inside that loop will run every frame. So anything that needs to run every frame must go inside that loop. The actual structure of the script looks like this:
 

global script slot2{
	void run(){
		//Everything that runs at the start of the game goes right here
		while(true){
			//Everything that runs every frame of the game goes here
			Waitframe();
		}
	}
}

Another thing that's often done with global scripts is to use functions to make it easier to read. For example, let's say I have a global script that... I dunno, sets Link's HP and MP to max every frame and also just gives him money. Why would I want that? I dunno. But let's pretend I did. It might look something like this:
 

global script slot2{
	void run(){
		while(true){
			Link->HP = Link->MaxHP;
			Link->MP = Link->MaxMP;
			Game->Counter[CR_RUPEES] += 1;
			Waitframe();
		}
	}
}

This is still a fairly simple global script. But you can start the see the issue. If I combine multiple scripts together, it might be hard to tell where one ends and the next begins. We can get around this by using functions.
 

void Russ_HpMpRupeeFunction(){
	Link->HP = Link->MaxHP;
	Link->MP = Link->MaxMP;
	Game->Counter[CR_RUPEES] += 1;
}

global script slot2{
	void run(){
		while(true){
			Russ_HpMpRupeeFunction();
			Waitframe();
		}
	}
}

Now in the global script, it's super clear and organized. Everything is still happening, but each individual script is organized into one single line, making it easy to tell what's actually running in the global script.

If you look at Moosh's pit script, you'll notice he already does this:
 

global script MooshPitGlobal{
	void run(){
		MooshPit_Init();
		while(true){
			MooshPit_Update();
			Waitframe();
		}
	}
}

There's a heck of a lot of code in Moosh's script, but because it's organized, it can be SUPER easily combined with other scripts. Unfortunately, the other two are slightly messier, but we can still make this work. When combining global scripts, there's only two things you need to do.

1. Everything between void run() and while(true){ in the separate scripts needs to be copy/pasted to that spot in your global script.
2. Everything between while(true){ and Waitframe(); needs to be copied to that spot in your global script.

There's likely a lot of other functions included in the script. But if they're not inside something labeled global script, don't worry about them! Copy paste them into your script file, but you don't need to merge anything with them. Now then, let's try this out with the three scripts you linked:
 

global script slot2{
	void run(){
		//Everything that runs at the start of the game goes right here
		//First, Moosh's pit script
		MooshPit_Init();
		
		//Next, Rob's red/blue blocks
		int lastScreen = Game->GetCurScreen();
        int lastMap = Game->GetCurMap();
        int lastLevel = Game->GetCurLevel();
		
		//Finally, MoscowModder's GB Shield
		bool shieldOn;
		while(true){
			//Everything that runs every frame of the game goes here
			//First, Moosh's pit script
			MooshPit_Update();
			
			//Next, Rob's red/blue blocks
			if(Game->GetCurScreen() != lastScreen || Game->GetCurMap() != lastMap || Game->GetCurLevel() != lastLevel)
			{
                lastScreen = Game->GetCurScreen();
                lastMap = Game->GetCurMap();
                lastLevel = Game->GetCurLevel();
                checkSwitchCombos(true);
            }
			if(CAN_WALK_ON_TOP)checkLinkOnRaised();
			
			//Finally, MoscowModder's GB Shield
			if( !shieldOn && shieldItem ){ //Enable shield when using dummy
				shieldOn=true; //Set shield state to on
				Link->Item[shieldItem]=true; //Give the shield
				Game->PlaySound(SFX_GBSHIELD); //Play the sound
			}
			else if( ( (shieldButton && !Link->InputA)||(!shieldButton && !Link->InputB)) //When button is released
					&& shieldOn){ //And shield is still on
				Link->Item[shieldItem]=false; //Remove shield
				shieldItem = 0; //Reset shield item variable
				shieldOn = false; //Set shield state to off
			}
			Waitframe();
		}
	}
}

And there we have it. All the scripts have been combined. Remember, there's a lot of other functions and constants included in those scripts, and all of those must be included in your script file. But as far as actually combining the global scripts, this is all it takes. One last point to make: Rob's script also has something called global script Init. And Init script is a special kind of global script that runs as soon as the game starts the first time. That global script doesn't need to be combined with the main script; we can just load it into slot 1 in the global scripts tab. If you need to combine multiple init scripts, it's similar to this; just copy paste everything between void run(){ and } in the various init scripts.

One last thing while we're here. This isn't necessary to do, so if you're confused, you can just stop reading at this point. You have a combined global script. But, if we wanted to make things easier to read, we could condense things into functions. Remember how I showed how my global script could all be put into a single line function, to make it easier to read? And how Moosh did that with his? We can do the same thing with Rob's and MoscowModder's scripts here too.
 

global script slot2{
	void run(){
		//Everything that runs at the start of the game goes right here
		//First, Moosh's pit script
		MooshPit_Init();
		
		//Next, Rob's red/blue blocks
		int lastScreen = Game->GetCurScreen();
		int lastMap = Game->GetCurMap();
		int lastLevel = Game->GetCurLevel();
		
		//Finally, MoscowModder's GB Shield
		bool shieldOn;
		while(true){
			//Everything that runs every frame of the game goes here
			//First, Moosh's pit script
			MooshPit_Update();
			
			//Next, Rob's red/blue blocks
			RobBlock_Update();
			
			//Finally, MoscowModder's GB Shield
			GBShield_Update();
			Waitframe();
		}
	}
}

void RobBlock_Update(){
	if(Game->GetCurScreen() != lastScreen || Game->GetCurMap() != lastMap || Game->GetCurLevel() != lastLevel)
	{
		lastScreen = Game->GetCurScreen();
		lastMap = Game->GetCurMap();
		lastLevel = Game->GetCurLevel();
		checkSwitchCombos(true);
	}
	if(CAN_WALK_ON_TOP)checkLinkOnRaised();
}

void GBShield_Update(){
	if( !shieldOn && shieldItem ){ //Enable shield when using dummy
		shieldOn=true; //Set shield state to on
		Link->Item[shieldItem]=true; //Give the shield
		Game->PlaySound(SFX_GBSHIELD); //Play the sound
	}
	else if( ( (shieldButton && !Link->InputA)||(!shieldButton && !Link->InputB)) //When button is released
			&& shieldOn){ //And shield is still on
		Link->Item[shieldItem]=false; //Remove shield
		shieldItem = 0; //Reset shield item variable
		shieldOn = false; //Set shield state to off
	}
}

Why would we do it this way? It makes it MUCH easier to read. If you're looking through the global script and want to know what's running every frame, it's pretty easy to understand:
 

		while(true){
			//Everything that runs every frame of the game goes here
			//First, Moosh's pit script
			MooshPit_Update();
			
			//Next, Rob's red/blue blocks
			RobBlock_Update();
			
			//Finally, MoscowModder's GB Shield
			GBShield_Update();
			Waitframe();
		}

If you wanted to remove a script, it'd be a one line deletion. You can name these functions whatever you want. You just have to make sure you cut and paste every part of the original, uncombined script between while(true){ and Waitframe(); into the function.

I hope all this makes sense. I'm happy to answer any questions if I've left you confused.

 

Thank you so much for the help and explanations, this actually really helped clear some of this stuff up for me. Now I was actually able to, I hope, successfully combine the scripts, however, when I try to compile it I get an error for line 535 that says "unexpected script, expecting identifier [line 535 column 11 'script']"

 

Looking at the line it is referring too, I don't see any issue, as there is an identifier there for an ffc script, or "ffc script" in the code followed by the name. Any idea what the issue could be?



#4 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 11 May 2020 - 06:42 PM

That compiler error is a bit confusing. Basically, it means it wasn't expecting it to find a new script on that line. That implies that whatever script or function you have above it is probably missing a } somewhere, so the compiler thinks it's still reading one script, then suddenly sees you starting another script. If you post you script file (if it's too big to post here, I suggest using pastebin and linking it here), I can take a look at it and see what's wrong with the script/function above it.



#5 Emily

Emily

    Scripter / Dev

  • ZC Developers

Posted 11 May 2020 - 06:59 PM

Russ, my script can NOT be done in a function. It uses local variables that are part of `void run()`, so splitting it into a function will get 'variable undefined' errors. I'd have split it into functions if it were possible, but things like that either need to eat global variables or be DIRECTLY in 'void run()'.



#6 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 11 May 2020 - 07:24 PM

Huh, yeah, I see that now. Writing global scripts that use local vars like that is pretty foreign to me, so it slipped my mind that people do that. Yeah, ignore that last bit I said in my first post, Sparks.

 

As for your new problem, Rob and I spotted the issue. The GB shield script actually has an error in it. The item script portion is missing a }. If you add one on a new line at the end of item script gbshield{, that should fix the problem.



#7 SparksTheUnicorn

SparksTheUnicorn

    Lonk, Hero of Lime

  • Members

Posted 11 May 2020 - 10:23 PM

Ok so I added in the bracket that was missing, which did fix the error, however now I am receiving this:

Line 428 @columns 21-68 - error T021: Function runffcscript(float, float) has not been declared.

Line 429 @ columns 11-17 - error S009: variable fcnum has not been declared.

Line 452 @ columns 21-68 - error T021: Function runffcscript(float, float) has not been declared.

Line 453 @ columns 11-17 - error S009: variable fcnum has not been declared.

 

here is the code if you want to take a look:

https://pastebin.com/1BRnkdz2



#8 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 11 May 2020 - 10:31 PM

Ah, it looks like one of your scripts needs ffcscript.zh. Download that and put it in your ZC folder, and import it at the top of you script just like you've imported std.zh. That should fix it up.


  • SparksTheUnicorn likes this

#9 SparksTheUnicorn

SparksTheUnicorn

    Lonk, Hero of Lime

  • Members

Posted 12 May 2020 - 12:44 PM

Ah, it looks like one of your scripts needs ffcscript.zh. Download that and put it in your ZC folder, and import it at the top of you script just like you've imported std.zh. That should fix it up.

That did it! Thank y'all so much for all your help! :)


  • Russ and Emily like this



Also tagged with one or more of these keywords: Help, Combining, Global, Question, Global Script, Combining Global Scripts

1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users