I think one reason scripting seems so hard is that there's a lack of useful guidance. Scripts aren't directly visible in quests, so you don't get much feedback aside from bug reports. Sure, there's a whole forum you can ask, but it's generally used for specific questions; it just doesn't feel like the right place to ask for general help with style and design. This thread is for precisely that. If you've got a script you'd like feedback on but no particular issues, or perhaps questions that feel too general or... let's say "squishy" to give their own thread, post them here.
We should probably have some guidelines...
Script posters
- Use code tags. Otherwise, the formatting gets screwed up and your script will be hard to read.
- If you're posting a long script, consider putting it in a hidden tag or linking to something like Pastebin to cut down on scrolling.
- Unless they're extremely short and simple, comment your scripts. No one else already knows how your script works. You can get away with fewer comments if the code itself is descriptive.
- Give at least a brief description of what your script does. If you want feedback on how a script performs, not just coding issues, you should include a demo or video. Otherwise, it's nice, but not at all essential.
- We'll assume you're including std.zh, but if your script uses any other headers, be sure to mention them.
- The main goal here is to help people become better scripters - to get comfortable with the language and logic and to develop good coding practices. Examples of how to do things and explanations of how they work and why they're done that way are helpful.
- Try not to give the impression that the way you would do something is the best or only way to do it. Except when it really is, of course.
- As long as they don't actually present problems, don't make too big a deal of things that are matters of personal preference - whitespace usage, naming conventions, things like that.
- Don't assume a script posted here is free to use. If it's not clear, ask first.
And don't feel insulted if you get a lot more explanation than necessary. We don't know how much you know, and it may be helpful for others reading.
It seems appropriate to include a script here to get things started. Here's a recreation of the ball shooter near the entrance of the Eastern Palace in LttP, as seen here. It's not too versatile because I wanted to keep it short and simple, but you're welcome to use it if you like.
// Ball settings. const int BSH_LARGE_BALL_COMBO = 888; // This should be a damage combo const int BSH_LARGE_BALL_CSET = 0; const int BSH_LARGE_BALL_SFX = 61; const float BSH_LARGE_BALL_SPEED = 1.5; const int BSH_SMALL_BALL_COMBO = 889; const int BSH_SMALL_BALL_CSET = 0; const int BSH_SMALL_BALL_SFX = 61; const float BSH_SMALL_BALL_SPEED = 1.5; // Number of small balls to shoot before shooting a large one. // If <=1, only large balls are fired. const int BSH_NUM_SMALL_BALLS = 5; // Time between balls. Must be at least 1. const int BSH_SHOT_TIMER = 60; ffc script BallShooter { void run() { while(true) { // Shoot however many small balls. Wait a bit before each shot. for(int ctr=0; ctr<BSH_NUM_SMALL_BALLS; ctr++) { Waitframes(BSH_SHOT_TIMER); ShootSmallBall(this); } Waitframes(BSH_SHOT_TIMER); ShootLargeBall(this); } } // Fires a small ball, randomly placed on either the left or right side // of the shooter. If there are no FFCs available, does nothing. void ShootSmallBall(ffc this) { // Get a free FFC. If there aren't any, return without firing. int ffcNum=FindFreeFFC(); if(ffcNum==0) return; ffc ball=Screen->LoadFFC(ffcNum); // Set up the ball. No need to keep track of it anywhere; // FFCs are automatically cleared when they go too far offscreen. ball->Data=BSH_SMALL_BALL_COMBO; ball->CSet=BSH_SMALL_BALL_CSET; ball->TileWidth=1; ball->TileHeight=1; ball->EffectWidth=16; ball->EffectHeight=16; ball->X=Choose(this->X, this->X+16); ball->Y=this->Y+16; ball->Vy=BSH_SMALL_BALL_SPEED; Game->PlaySound(BSH_SMALL_BALL_SFX); } // Fires a 2x2 tile ball. If there are no FFCs available, does nothing. void ShootLargeBall(ffc this) { int ffcNum=FindFreeFFC(); if(ffcNum==0) return; ffc ball=Screen->LoadFFC(ffcNum); ball->Data=BSH_LARGE_BALL_COMBO; ball->CSet=BSH_LARGE_BALL_CSET; ball->TileWidth=2; ball->TileHeight=2; ball->EffectWidth=32; ball->EffectHeight=32; ball->X=this->X; ball->Y=this->Y; ball->Vy=BSH_LARGE_BALL_SPEED; Game->PlaySound(BSH_LARGE_BALL_SFX); } // Finds an unused FFC to use for a ball and returns the number of // that FFC. Returns 0 if there are none available. int FindFreeFFC() { for(int num=1; num<=32; num++) { // An FFC is considered to be unused if // it has no combo or script set. ffc f=Screen->LoadFFC(num); if(f->Data==0 && f->Script==0) return num; } return 0; } }