I've tried something similar myself, and I'm sorry to say it doesn't quite work. If Link's health hits 0, he dies instantly, and no script can save him. As long as he has some life left, though, it'll work fine.
ffc script invulnerability_script_001;
...
void run();
...
while(D[2] = 1);
Those semicolons shouldn't be there. Anything that's followed by curly braces shouldn't have a semicolon.
The worst part is that that isn't always invalid. Putting a semicolon after a while statement is perfectly acceptable, but it's equivalent to [font="Courier New"]while(...) { }[/font]. In other words, if the condition is true, it'll do nothing forever, causing the game to hang.
void run(); // <-- No idea what this does; it's simply a tradition to me.
The statement [font="Courier New"]void run()[/font] marks the beginning of the run() function (if you don't know how to interpret function headers, I'll be glad to explain). When a scripted FFC appears, the game automatically calls this function. So, in effect, this simply tells the game where to start running the script. It's comparable to main() in C.
float D[1] = int HP; // <-- "float D[1] is the right syntax, right? Otherwise, the line sets the value of the variable D[1] to whatever Link's HP is at the moment. It then goes into a while loop in a bit and won't leave. float D[2] = 1; // <-- Setting a switch. Purely for paranoia reasons.
Hm... Okay, lemme go over variables and pointers real fast...
A variable, as I think you know, is basically a place to store data. There are three types of variables in ZScript: ints/floats (numbers - never mind why there are two names for the moment), bools (true or false), and void (nothing - again, never mind that for now).
There are also several pointer types; a pointer is similar to a variable, in that they're both places to store data. Pointer types include link, screen, game, ffc, and others. In many cases, there's just one pointer of each type; for example, the only link pointer is Link, and the only game pointer is Game.
The difference between a pointer and a variable is that pointers indicate complex data types that have their own personal sets of data, called data members. These are accessed using the arrow operator; for example, Link's HP is accessed via [font="Courier New"]Link->HP[/font]. Similarly, screen variables are accessed using [font="Courier New"]Screen->D[x][/font].
With few exceptions (screen and global variables are the only ones, I think), changing the value of a pointer's data member directly affects the game in some way, while changing a regular variable's value does not.
Now, you also have to know about declaring variables. The built-in pointers, like Link, this, Screen, and so forth don't have to be declared, and neither do their data members. Any other pointers or variables must be declared before they're used, and must only be declared once. Variables and pointers are declared by preceding their names by their types, like so:
int x; // Declare a variable named x of type int
x = 5; // Set x's value to 5
int y = x; // Declare a variable named y of type int and set its value to x's value
int y; // Error: y was already declared.
So... Where were we?
float D[1] = int HP; // <-- "float D[1] is the right syntax, right? Otherwise, the line sets the value of the variable D[1] to whatever Link's HP is at the moment. It then goes into a while loop in a bit and won't leave. float D[2] = 1; // <-- Setting a switch. Purely for paranoia reasons.
Ah, right. Well, it appears you mean to store Link's HP into D[1]. D[1] and Link's HP are data members of Screen and Link, respectively, so the necessary code is this:
Screen->D[1] = Link->HP;
You could also avoid the screen variables altogether and simply declare your own variable:
int storedHP = Link->HP;
That's safer if you're using this along with other scripts, since the others might change D[1] themselves.
One thing to mention about that, though: in previous betas, that variable might not have been local, as it should be. I think it's been fixed, but watch for problems if you change it.
As for the 1 in D[2], you don't need that, for reasons I'll get to shortly.
By the way, the variables are numbered 0-7, not 1-8, so the first of the screen variables is Screen->D[0].
while(D[2] = 1);
The semicolon I already covered.
Also important is the equals sign. You need one equals sign for assignment and two for comparison. That is, you should write [font="Courier New"]Screen->D[2] == 1[/font] for this comparison.
However, you don't need to do this at all. The simplest expression that'll always evaluate to true:
while(true)
int HP = D[1]; // <-- Sets the value of Link's HP to the value of D[1]. Waitframe(); // <-- The infamous Waitframe.
Not much to say here; already went over variables, and the Waitframe() is there. Basically, this just needs to be:
Link->HP=Screen->D[1];
Waitframe();
So, in short, the completely rewritten version of this script (minus comments):
ffc script invulnerability_script_001
{
void run()
{
Screen->D[0] = Link->HP; while(true)
{
Link->HP = Screen->D[0];
Waitframe();
}
}
}
And the alternate version, avoiding the screen variable:
ffc script invulnerability_script_001
{
void run()
{
int storedHP = Link->HP; while(true)
{
Link->HP = storedHP;
Waitframe();
}
}
}