Reply to Re: magicman's rant about scripting techniques
If you don't have an account, just leave the password field blank.
There seems to be some interest in more of these things, so I've started writing a rant about how and why I wrote Persistent Loot the way it is. I'll probably finish it later this week. Until then, have a mini-rant about a cool technique that you can use with "Fancy functions":
Introducing: Optional parameters
Let's start with a bit of code:
Now, a call to external("stuff","remove"); will remove ¤t_sprite from the game. Now, in a lot of cases, this is what you want. In some cases, I'd love to remove a different sprite from the game. So. What are my options?
Change ¤t_sprite to &arg1 in void remove( void ), then add ¤t_sprite as an argument everywhere I call it using external()? That seems like a good option, though I don't look forward to doing a big search-and-replace.
Not use external() at all for those few cases? It would work, but that kind of beats the purpose of separating out code.
In my opinion, the best solution to this problem is to consider what happens when you don't pass a parameter, but use &arg1 anyway: its value will be 0. Since 0 is never a valid sprite number, we can check for that, and deal with it accordingly. The code is now:
Alternatively, the first bit can set &sprite to &arg1, and only set it to ¤t_sprite if &arg1 turns out to be 0.
When designing procedures with default arguments, I recommend that you order the arguments by how often you expect to use a non-default value. For example, if you have a procedure with 3 arguments, of which the first is required, and the second and third have a default, you can pass in the first two, and the third will use the default value.
The main caveat: Occasionally, you may want to pass in 0! Sadly, external("stuff","remove"); and external("stuff","remove",0) do exactly the same thing, and are indistinguishable.
Also beware when entering variables, the following code may have dire consequences:
If there are no brain 9 sprites on the screen, get_sprite_with_this_brain will return 0. This means that ¤t_sprite will be removed from the game!
Summary
If you don't pass an argument to a call to external(), its corresponding &arg1 to &arg9 variable will be 0. You can check for this, and do something sensible as default.
Beware when you want to pass 0, and for cases where you can accidentally pass 0.
Introducing: Optional parameters
Let's start with a bit of code:
// stuff.c void remove( void ) { int &ednum = sp_editor_num(¤t_sprite); if (&ednum > 0) { editor_type(&ednum,1); } sp_nodraw(¤t_sprite,1); sp_nohit(¤t_sprite,1); sp_active(¤t_sprite,0); }
Now, a call to external("stuff","remove"); will remove ¤t_sprite from the game. Now, in a lot of cases, this is what you want. In some cases, I'd love to remove a different sprite from the game. So. What are my options?
Change ¤t_sprite to &arg1 in void remove( void ), then add ¤t_sprite as an argument everywhere I call it using external()? That seems like a good option, though I don't look forward to doing a big search-and-replace.
Not use external() at all for those few cases? It would work, but that kind of beats the purpose of separating out code.
In my opinion, the best solution to this problem is to consider what happens when you don't pass a parameter, but use &arg1 anyway: its value will be 0. Since 0 is never a valid sprite number, we can check for that, and deal with it accordingly. The code is now:
// stuff.c void remove( void ) { // Set new variable (with descriptive name!) to default value. int &sprite = ¤t_sprite; if (&arg1 != 0) { // Oy, we actually have a value. Better set the variable to that. &sprite = &arg1; } int &ednum = sp_editor_num(&sprite); if (&ednum > 0) { editor_type(&ednum,1); } sp_nodraw(&sprite,1); sp_nohit(&sprite,1); sp_active(&sprite,0); }
Alternatively, the first bit can set &sprite to &arg1, and only set it to ¤t_sprite if &arg1 turns out to be 0.
When designing procedures with default arguments, I recommend that you order the arguments by how often you expect to use a non-default value. For example, if you have a procedure with 3 arguments, of which the first is required, and the second and third have a default, you can pass in the first two, and the third will use the default value.
The main caveat: Occasionally, you may want to pass in 0! Sadly, external("stuff","remove"); and external("stuff","remove",0) do exactly the same thing, and are indistinguishable.
Also beware when entering variables, the following code may have dire consequences:
void talk( void ) { int &sprite = get_sprite_with_this_brain(9, ¤t_sprite); external("stuff","remove",&sprite); }
If there are no brain 9 sprites on the screen, get_sprite_with_this_brain will return 0. This means that ¤t_sprite will be removed from the game!
Summary
If you don't pass an argument to a call to external(), its corresponding &arg1 to &arg9 variable will be 0. You can check for this, and do something sensible as default.
Beware when you want to pass 0, and for cases where you can accidentally pass 0.