Need help with sfall scripting!

Magnus

Water Chip? Been There, Done That
Modder
I want to change the AP costs of the unarmed special attacks. For that I'll use the hookscript hs_calcapcost.int. The problem is I've never done any Fallout2 scripting before and don't know the syntax, how scripts get initialized, what's allowed and what's not, etc. I want to have a global script that checks every other frame to see if the character does not have a weapon equipped, and if so, allows the calcapcost hookscript to run. Here's how the scripts looks so far:

Code:
//gl_F2WRUnarmedAP.int

procedure start;
#include "..\headers\define.h"
procedure modAP;

procedure start begin

 // This should make the script run every 3 frames to check equipped weapons
 set_global_script_repeat(3);

end

procedure modAP begin

 // I have NO idea if this is correct syntax

 // If the object at the dude's active hand is currently nothing (unarmed), then let the hook run
 if (critter_inven_obj(dude_obj, active_hand) == NULL)  

  // How does this work?
  register_hook(2);

 end
end
Code:
//hs_calcapcost.int
procedure start begin
  variable type;
  if (hook_init == 0) then begin

    type:=get_sfall_arg;
    type:=get_sfall_arg;

    if (type == 6) or (type == 8)
      set_sfall_return(4);
    end
    if (type == 7) or (type == 9)
      set_sfall_return(5);
    end

  end
end

So, there's probably plenty of things that's wrong with this. Would anyone care to point out exactly what? Also, if they were right, could I just compile them, put them in the scripts folder and they'd run?
 
Magnus said:
So, there's probably plenty of things that's wrong with this. Would anyone care to point out exactly what?
It's actually pretty good for a first guess. You're trying to do it a slightly different way to what I was originally suggesting though, and I don't think it's going to work; you're going to end up changing the ap cost of moving if the critter happens to move 6/7/8/9 hexes at once. You really need to compare the 2nd argument of the hook script rather than the 4th. (Plus there are some syntax issues, and register_hook doesn't work in quite the way you think it does, but you can ignore that for now.)

I thought I remembered nirran working out which number was which ap cost calculation, but doing the search myself I seem to have confused it with the get_attack_type codes, so you're going to have to do your own research. Do something like this:

Code:
//hs_calcapcost.int
procedure start begin
  variable args[4], i;
  for i:=0; i<4; i++; args[i]:=get_sfall_arg;
  if args[0]==dude_obj and args[3]>=6 and args[3] <=9 then begin
    display_msg("For AP cost: "+args[3]+" arg2: "+args[1]+" arg3: "+args[2]);
  end
end
Then go in game and make the various unarmed attacks, and make a note of the numbers that appear in the console. You can use them in the real script.

Magnus said:
Also, if they were right, could I just compile them, put them in the scripts folder and they'd run?
Yup, anything starting with gl is a global script, and anything with hs is a hook script. They'll get run automatically at the appropriate times, and don't need to appear in scripts.lst.
 
Thanks for the headsup. Heh, should have thought of the AP cost for moving. I wasn't sure if the language even supported for loops, it looks much tidier now. I'm guessing it isn't object-oriented, so I should call the procedures with dude_obj as a parameter instead of as a method of obj_dude.

How does register_hook work then, and what syntax issues are there?'

Again, thanks.

EDIT: I've edited the code to what seems to be more correct syntax. Does the procedure prototyping actually call the procedures, or do I have to do that specifically?
 
Since it's sfall getting in the way of your mod, I've done the testing and written the script you need for you. Turns out the numbers you need are exactly the same as those from get_attack_type, so you can use the defines that already exist in sfall.h. Just compile this, make sure it's named 'hs_calcapcost.int' and dump it in the scripts folder.

Code:
#include "sfall.h"

procedure start begin
  variable type, aimed, i;
  if not init_hook then begin
    type:=get_sfall_arg;
    type:=get_sfall_arg;
    aimed:=get_sfall_arg;
    i:=-1;
    if type == ATKTYPE_PALMSTRIKE or type == ATKTYPE_PIERCINGSTRIKE or type == ATKTYPE_JAB then begin
      i:=4;
    end
    if type == ATKTYPE_HIPKICK or type == ATKTYPE_HOOKKICK or type == ATKTYPE_PIERCINGKICK then begin
      i:=5;
    end
    if i != -1 then begin
      if aimed then i++;
      set_sfall_return(i);
    end
  end
end


Magnus said:
I wasn't sure if the language even supported for loops, it looks much tidier now.
It doesn't. Luckily sfall has a rather extensive script extender. :P (actually, the for loops are just a compiler trick. They get compiled down into a while loop as soon as your back's turned.)

Magnus said:
I'm guessing it isn't object-oriented, so I should call the procedures with dude_obj as a parameter instead of as a method of obj_dude.
yup. There are some functions which implicitly operate on the critter whose script is running though, so for those functions you need to use 'set_self(dude_obj);' first. There's certainly no object orientation though.

Magnus said:
How does register_hook work then, and what syntax issues are there?'
Syntax issues were you trying to use .'s in an object oriented way. register_hook causes the global script itself to be used as a hook script. It's not needed to use the specially named hook scripts. global scripts that call register_hook should not call set_global_script_repeat or set_sfall_return either. (set_sfall_return because obviously only one hook script can override the return value and the hs_xxx scripts take priority, and set_global_script_repeat because you wouldn't know if your script was being called as a global script or becuase of a hook.)

Magnus said:
Does the procedure prototyping actually call the procedures, or do I have to do that specifically?
There are some special named procedures that get called automatically at appropriate times, (Just start in global/hook scripts, but plenty more on critters/maps/etc.) but for the most part you need to call the procedures youself.
 
ahhhhhh, so arg2 is the attack type! That makes it a whole lot easier. Is there a limit to what a hook script can do if you just include the right headers? Also, I guess this breaks compatibility with any other mod that uses calcapcost.

A++ mate, this will help a lot, and I feel like I can learn further scripting on my own now. Thanks!

EDIT: I can't compile it, because sfall.h is never included. According to your own documentation, won't the procedure start be run before the include? Should I just use the int values instead?
 
nice that arg 2 is attack type

you should add checks for 'Bonus HtH Attacks" perk,and lower ap cost accordingly(assuming you want it to be affected by the perk)

just a suggestion

Nirran
 
Magnus said:
EDIT: I can't compile it, because sfall.h is never included. According to your own documentation, won't the procedure start be run before the include?
sfall.h is in the modders pack, in the same folder as the scripting info. Just make sure it's somewhere where the preprocessor can find it. (or you can remove the #include and manually replace the ATKTYPE_XXX defines with their respective numbers.)

It's having other procedures defined before start that causes the problems, but sfall.h doesn't contain any so it's safe. For the sake of sticking to my own rules though, you can add a 'procedure start;' line before the #include if you like.

Nirran said:
you should add checks for 'Bonus HtH Attacks" perk,and lower ap cost accordingly(assuming you want it to be affected by the perk)
Ah, good point. I forgot about those...

I was originally going to do it like this:
Code:
  type:=get_sfall_Arg
  aimed:=get_sfall_arg;
  orig:=get_sfall_arg;
  if type == ATKTYPE_PALMSTRIKE then begin
    set_sfall_return(orig-3);
  end
  <etc for the other attack types>
That would take care of the effects of perks, but it would have required me to look up the original ap costs to find out how much I needed to subtract. :P
 
Here's how the script looks now:

Code:
procedure start;
#include "sfall.h"
#include "DEFINE.H"

procedure start begin
  variable type, aimed, i;
  if not init_hook then begin
    type:=get_sfall_arg;
    type:=get_sfall_arg;
    aimed:=get_sfall_arg;
    i:=-1;
    if (type == ATKTYPE_PALMSTRIKE) or (type == ATKTYPE_PIERCINGSTRIKE) or (type == ATKTYPE_JAB) then begin
      i:= 4 - (has_trait(TRAIT_PERK, dude_obj, PERK_bonus_hth_attacks) > 0);
    end
    if (type == ATKTYPE_HIPKICK) or (type == ATKTYPE_HOOKKICK) or (type == ATKTYPE_PIERCINGKICK) then begin
      i:=5 - (has_trait(TRAIT_PERK, dude_obj, PERK_bonus_hth_attacks) > 0);
    end
    if i != -1 then begin
      if aimed then i++;
      set_sfall_return(i);
    end
  end
end

I've got it in a folder with compile.exe, DEFINE.H and sfall.h, and I run compile.exe with the script name as parameter. It doesn't recognise ATKTYPE_PALMSTRIKE, which leads me to believe it never includes sfall.h. Should I just get rid of the definitions and replace them with the respective integers? I'd still have to include something for the dude_obj, but I guess there's another way to do it.

EDIT: Ah, I do not have a preprocessor, which is apparently required for # commands like include. Where can I get one and how do I use it? I have Visual Studios 2008, is that any good?

EDIT AGAIN: Nevermind, found one and got it to work. I now have a hs_calcapcost.int, hope it works!

EDIT ONCE AGAIN: Haha! It works like a charm! Thanks a lot dudes :)
 
Hmm, I have some question as well. Hope it's okay, if I ninja-capture the thread for a second. :>

It's about the way to add new elevators with using sfall. Thought this would be easy, as I simply saw a new elevators.ini file in the restoration project and created my own. I've set up an elevator "the old way" (check out Coljacks old stuff, in case you don't know) and simply changed elevator type number to one of my new ones. But this doesn't work. The interface for the elevator doesn't work at all.

Now my question is, does it work different with sfall, if I want to add new ones? Do I need unique scripts for it? Because I saw in the RP maps, that the elevators there got their own scripts. Never checked it out before, always just thought "cool, sfall allows me new elevators now". :P
 
Did you change the relevant ddraw.ini setting (can't remember the name off hand, sorry,) to point at your elevators.ini?

I've never tried placing new elevators like that; I've always either modified existing ones or used the show-elevator-menu metarule for new ones.
 
Ardent said:
where can I find the mentioned sfall.h?

In the modders' pack, in the folder "sfall scripting".

Sorry for the n00b question, but where's the "modders' pack"? I can't find anything with that label in the files area or via forum search... could you please provide a link to what you're talking about for us relatively-inexperienced modders?

Thanks,
-m
 
I've been having a lot of trouble with global scripts: usually when I use more than one or two at a time I get problems such as endless loading times after every couple of map entries. First I thought it was just a matter of a lot of simultaneous activity at the beginning of the map overloading things (the scripts usually involve checking all the critters on a map), but then I noticed that delaying the scripts with timed events didn't help much either.

Debug mode wasn't much help because everything was fine when using it, until I recently tried making a global script with this in it:
Code:
foreach critter in list_as_array(LIST_CRITTERS) begin
         if (obj_art_fid(critter) == FID_HAROBE)... etc.

This caused the game to crash after a couple of map entries with the debug message: "Error during execution: script error: scripts\glcritters.int: invalid arg to obj_art_fid". Unless I'm mistaken and my tests were wrong*, this means that the game found a "critter" in LIST_CRITTERS which didn't have an obj_art_fid, which should mean it's not really a critter, right? Or am I on the wrong track here? I'm probably grasping at straws, but if there were some type of problem with the LIST_CRITTERS then that would explain a lot of my problems.

*: When I put the exact same sequence in the dude script (except with "critter" replaced by dude_obj of course, then there wasn't a single problem).

EDIT: Found the problem (at least I hope)! Switched all the script types from 1 (almost always active) to 0 (regular script loop) and everything is working together nicely.
 
Different question:

When I use set_critter_stat, the value always reverts back to the original the moment I leave the map. I always naïvely thought that this was normal, but gathering from examples on the site and in the game, it seems that set_critter_stat is meant to be saved. I was thinking maybe the problem is the modding method I use, which is with a Patch000.dat folder with the maps folder write protected; is this maybe keeping the values from being saved at map exit?

And if I'm wrong after all, and set_critter_stat is meant to be temporary, then is there a way to make this permanent (maybe with the virtual file system or something)?

EDIT: An extra question:

How am I supposed to use the get_script function? It returns an 8-digit number which is unique for each individual critter (even if their scripts are the same).

What I need it for, is that I want to be able to set the script of one critter with that of another.

EDIT: Only just realized how stupid my first question was; of course only the player's and party members' (non-current hit point) stats get saved after map exit. Would still like an answer to the second question though.
 
Back
Top