Fallout 2 mod FO2 Engine Tweaks (Sfall)

Looks like compile.exe not longer runs under XP SP3. I'm getting a "Invalid Win32 application" error. I guess you're compiling it with the latest Visual Studio like you do with ddraw.dll?
Judging from sslc.vcxproj, it's now compiled with v110 toolset instead of v110_xp, so it doesn't support WinXP/2003.
Switching the toolset might work, but currently I'm home and don't have my compile environment. :\
 
Last edited:
Could you include compile.exe in your unofficial compiles too, to make it run on old OS's?

Thanks in advance.


As for the Script Editor: does anyone know why it doesn't show on-mouse-over MSG's text in script window if there's a comment (or any other character, including space) after the brackets?

Code:
{}{}{} #

I'm using 2.15.
 
Could you include compile.exe in your unofficial compiles too, to make it run on old OS's?
Sure, that's what I was planning to do. I just finished testing on my XP SP3 machine.

Here's my unofficial sfall compiles, updated to the newest 3.3 sources (SVN r271): (removed due to newer updates)

The package includes three DLLs:
  • the one in the root directory of the archive - normal sfall for WinXP SP3 or later, compiled with SVN r271 (credits updated, the comment about Interplay removed) in order to match the debugging one from 3.3 modders pack.
  • win2k - for Win2000 or WinXP RTM/SP1/SP2.
  • win2k_trace - the "debugging" version for modders on older OSes.
There are also two versions of sslc (compile.exe):
  • sslc_xp - compiled with VS2012-WinXP (v110_xp) toolset, supports WinXP SP3 and Win2003 SP2 (what, can't I play Fallout and stuff on my testing server? :P)
  • sslc_win2k - compiled with VS2008 (v90) toolset, should support Win2000 or WinXP RTM/SP1/SP2 (not fully tested yet).
The included ddraw_adv.ini has almost all settings recognized by sfall. The only settings not included are debugging settings (they only work with debugging DLLs), main menu offsets (currently only useful for FO1 to FO2 conversion) and NPC combat controls.

@Timeslip
You might want to update sslc and its project file in the next release, since IMO there's no obvious advantage using pure VS2012 toolset for it.

EDIT: Judging from the increased number of downloads, looks like modders still working on WinXP are more than I thought.
 
Last edited by a moderator:
Does anyone update the decompiler (int2ssl) that used with Script Editor when you open int files? Looks like it fails to decompile scripts that was compiled with new custom sfall functions in it (specifically gdialog_get_barter_mod). Scripts themselves are working fine in game.

Edit: Found very strange behavior (using latest sfall and compiler)... When I try to define negative float value directly:
Code:
display_msg(""+(-1.0));
or when I try to multiply negative integer with positive float:

Code:
display_msg(""+((-1)*1.0));

.. I end up with very strange values like -12431251515.00000

Not sure if it's related to sfall or not, but I've found a somewhat limited workaround for this:
Code:
atof("-"+(-var))
where var - is negative integer that you wish to multiply. To make float, I think you'll have to divide it somehow...
 
Last edited:
Does anyone update the decompiler (int2ssl) that used with Script Editor when you open int files? Looks like it fails to decompile scripts that was compiled with new custom sfall functions in it (specifically gdialog_get_barter_mod). Scripts themselves are working fine in game.
Have you tried the one from Nirran's site? It should support those new sfall functions.
 
There is way to decrease/increase perk freq? What values I need to use to get example perk for every 2 level, instead of default 3?
This global script will give you a perk every two levels:

Code:
procedure start begin
    if (game_loaded) then begin
        set_perk_freq(1);
    end
end

I made this script using Script Editor then I Compile it to .int file. I replaced glkagako.int file with my new script. Perk window appear every lvl but its empty/black and I can't choose anything. Any idea what's went wrong?
 
improved Script Editor

So I've been sick of some of the shortcomings of Script Editor and decided to tweak it a little bit. Changes so far:

1) Pressing Ctrl+F always gives focus to Search Text field (in some cases it didn't before)
2) Pressing Esc in Search window - closes it
3) Editor Settings are now stored in Current Working Directory, instead of Users directory (can have two editors with different compile script paths for example)
4) Added 2 options in Settings window: Convert Tabs to spaces and Tab size
5) (hopefully) fixed a nasty bug: when using code Tree View to the right it showed last parsed tab, instead of currently opened
6) Made it so all fallout/sfall script commands will be highlighted (sfall commands in bold).
7) Errors tab is opened upon unsuccessful compile
8) Implemented extremely simple drag-n-drop reordering of Tabs
9) Added GoTo Line command
10) Added commands "UPPERCASE" and "lowercase" selected text
11) Fixed Close Tab in buttom tab control closing document instead
12) Added "Close All" and "Close all but this" commands
13) Fixed "Replace All" corrupting document when search string had different length than replace string
14) Visually improved Code Navigator (treeview)
15) When closing current tab, last tab becomes active instead of first
16) Ability to drag&drop files into Script Editor

I'm not using Source Forge so I won't make proper fork for this, maybe just upload my source changes somewhere when I'm done.

Here's a download: https://yadi.sk/d/EJjRGyFeYvJRo, there are
- all features listed above
- decompiler from Nirran's website that work with any script

It's a test build though, there may be new bugs introduced.

EDIT: this download is now obsolete since new editor is included in latest sfall modderspack
 
Last edited:
Continuum said:
I'd like to have Barter button conditional, controlled via script, not by some Yes/No in critter's proto I can only set in Mapper.

I'm stuck on this same issue. Generally speaking the answer is probably over here but I don't understand how to translate the info there into a method to find out the particular way to toggle the barter function.

Does anyone know anything about this issue?
 
I'm stuck on this same issue. Generally speaking the answer is probably over here but I don't understand how to translate the info there into a method to find out the particular way to toggle the barter function.

Does anyone know anything about this issue?

I haven't tried it, but I'm using similar approach with several things (like changing item selling prices by going over all PROTOs in memory and changing them, or making molotov cocktail show explosion but at the same time inflict fire damage):
Code:
var flags := get_proto_data(0x01000000+356, 32);
flags := flags bwxor 0x00000002; // bwxor to disable barter, bwor to enable
set_proto_data(0x01000000+356, 32, flags);
0x01000000+356 - is a critter prototype (I write it this way for clearer number, you may use plain number instead).
32 - prototype offset.

You may have to adjust flag offset or proto data offset. Refer to this page: http://falloutmods.wikia.com/wiki/PRO_File_Format
But beware that those offsets are for prototypes in files. In memory they are stored not quite in the same order (mostly they are, but there may be differences).
 
@phobos2077

Thanks. I copied what you wrote and it sort of works, and most likely the remaining trouble is because I merely pasted what you wrote without really understanding yet how the function works. I'd appreciate any additional help or explanations on this issue.

Here's my situation: For a long time now I've had an expanded and enhanced version of the Bess the Cow mod found in the Megamod, and I'm trying to polish it up for release. Part of my mod is that Balthas the Tanner in Modoc can make some saddlebags for Bess, so she can haul around some of the Chosen One's gear. Otherwise, lacking hands, she isn't able to carry anything. In the past I've just used simpler set_critter_stat to toggle her carry-weight between 0 and 500 pounds depending on whether she has the saddle-bags on, but while that's fine for my own game I think other people might get confused and it would be better to toggle the Barter function on or off instead.

Based on the example phobos2077 gave, I wrote the following (in talk_p_proc). In this mod Bess also has several level-up protos to complicate matters, so rather than use a fixed value I instead used a variable for her critter pid. Local variable 9 records whether or not Bess is wearing the saddle-bags.

Code:
    variable myself := 0;
    variable flags := 0;
    myself := op_obj_pid(op_self_obj());
    flags := op_get_proto_data(myself, 32);
    if (op_local_var(9) == 0) then
    begin
          flags := flags bwxor 0x00000002;
          op_set_proto_data(myself, 32, flags);
    end
    if (op_local_var(9) == 1) then
    begin
          flags := flags bwor 0x00000002;
          op_set_proto_data(myself, 32, flags);
    end

Here's the weird part: using this code, the barter function toggles itself in between conversations with Bess when she is not wearing the saddle-bags (local var 9 == 0).

In other words, it works like this:

1) Talk to Bess. Press "trade" button. Message is properly displayed-- "This critter cannot barter."
2) End conversation and exit dialogue interface.
3) Talk to Bess again. Press "trade" button. The trading interface comes up and items can be traded.
4) Exit trade interface, end conversation and exit dialogue interface.
5) Talk to Bess again. Press "trade" button. Message is properly displayed-- "This critter cannot barter."
6) And so on, in alternating cycles.

Once Bess is wearing the saddle-bags (local var 9 = 1), the function works at all times and she can always barter. Also, the local variable is not itself altered in the talk_procedure, so it's not a problem with something funky going on elsewhere in my script. :wiggle:

Anybody have any ideas on what's happening in this strange situation? I can sort of see why this might happen (modifying the data on the fly changes the underlying reference), but don't know what to do about it.
 
@Endocore,
It's my mistake. Incorrectly setting flag off. Here is proper method:
Code:
if (op_local_var(9) == 0) then
    begin
          flags := flags bwand INV(0x00000002);
          op_set_proto_data(myself, 32, flags);
    end

You will need this directives from COMMAND.H:
Code:
#define MAXINT 4294967295                 //Max int
#define INV(x) (MAXINT - x)               //An inverse function


PS: my version of sfall Script Editor has been updated, see post above
 
Last edited:
Don't know if anyone has tried inc_npc_level and get_npc_level functions. Just posting my testing results and findings. Both functions use NPC names from scrname.msg (not case-sensitive), so changing names in the msg will break any script contains them.
That also means scripts have to be localized and re-compiled if any localized game changes NPC names in scrname.msg, or at least NPC names called by both functions shouldn't be localized/changed in scrname.msg.


Here's an example: gl_npcmaxlv, a cheating global script that automatically levels up all NPCs in party to their max level:
Code:
procedure start;
#include ".\HEADERS\DEFINE.H"
#include ".\HEADERS\sfall.h"

procedure start begin
   if (game_loaded) then begin
      set_global_script_repeat(60);
   end else begin
      if (party_size > 1) then begin
      // NPC names from scrname.msg
         if (get_npc_level(mstr_scrname(483)) < 6) then begin
            inc_npc_level(mstr_scrname(483)); // Sulik
         end
         if (get_npc_level(mstr_scrname(150)) < 6) then begin
            inc_npc_level(mstr_scrname(150)); // Vic
         end
         if (get_npc_level(mstr_scrname(672)) < 4) then begin
            inc_npc_level(mstr_scrname(672)); // Cassidy
         end
         if (get_npc_level(mstr_scrname(239)) < 4) then begin
            inc_npc_level(mstr_scrname(239)); // Lenny
         end
         if (get_npc_level(mstr_scrname(700)) < 5) then begin
            inc_npc_level(mstr_scrname(700)); // Marcus
         end
         if (get_npc_level(mstr_scrname(537)) < 4) then begin
            inc_npc_level(mstr_scrname(537)); // Myron
         end
         if (get_npc_level(mstr_scrname(267)) < 5) then begin
            inc_npc_level(mstr_scrname(267)); // Brain Bot
         end
         if (get_npc_level(mstr_scrname(573)) < 4) then begin
            inc_npc_level(mstr_scrname(573)); // Robodog
         end
         if (get_npc_level(mstr_scrname(647)) < 6) then begin
            inc_npc_level(mstr_scrname(647)); // Goris
         end
         if (get_npc_level(mstr_scrname(1157)) < 4) then begin
            inc_npc_level(mstr_scrname(1157)); // K-9
         end
         if (get_npc_level(mstr_scrname(1195)) < 6) then begin
            inc_npc_level(mstr_scrname(1195)); // Dogmeat
         end
      // RP 2.x new NPCs
         if (get_npc_level(mstr_scrname(1506)) < 5) then begin
            inc_npc_level(mstr_scrname(1506)); // Dex
         end
         if (get_npc_level(mstr_scrname(1507)) < 5) then begin
            inc_npc_level(mstr_scrname(1507)); // Cat Jules
         end
         if (get_npc_level(mstr_scrname(1508)) < 5) then begin
            inc_npc_level(mstr_scrname(1508)); // Kitsune
         end
      end
   end
end
If you change {483}{}{Sulik} to {483}{}{Bonenose} in scrname.msg, the script won't level Sulik up.
 
Last edited:
Found another problem with SSLC: it removes push_p_proc as unreferenced procedure if you use optimize mode 1. It was actually the source of problem when I couldn't push Vic away (I adjusted his script and recompiled as usual) in my mod.

Beware anyone who's using Basic optimization!

A list of missing lines in optimize.h, IsProtectedProc(const char* c):
Code:
     Protect("push_p_proc");
     Protect("drop_p_proc");
     Protect("is_dropping_p_proc");
     Protect("create_p_proc");

Could someone correct this and recompile?

Edit: Recompiled it with VS 2010.
 
Last edited:
My unofficial sfall compiles updated to SVN r273b (3.3.1.2731): (removed due to newer updates)

Mash added a fix for script function obj_can_see_obj:
Allows objects to see through other objects which have their shootthru flag set. Disabled by default as I wasn't sure if it would have a negative impact in some situations. Set ObjCanSeeObj_ShootThru_Fix=1 under Misc in ini to enable. - Mash
phobos2077 fixed a bug in string_split function, and sslc compiles have the bugfix for optimize mode 1 from his post above.

The package includes four DLLs:
  • the one in the root directory of the archive - normal sfall for WinXP SP3 or later.
  • trace - the debugging version.
  • win2k - for Win2000 and WinXP RTM/SP1/SP2.
  • win2k_trace - the debugging version for modders on older OSes.
There are also two versions of sslc (compile.exe):
  • sslc_xp - compiled with VS2012-WinXP toolset (v110_xp), supports WinXP SP3 or later.
  • sslc_win2k - compiled with VS2008 toolset (v90), should support Win2000 and WinXP RTM/SP1/SP2 (not fully tested yet).
The included ddraw_adv.ini has almost all settings recognized by sfall. The only settings not included are debugging settings (they only work with debugging DLLs), main menu offsets (currently only useful for FO1 to FO2 conversion) and NPC combat controls. [strike]The setting for Mash's new fix isn't included too, because it's not been tested yet.[/strike]


P.S.: Not sure next time should I release sfall and sslc in two archives, given that the total file size is somewhat large now.
 
Last edited:
^ Say, what's with the combat controlls? I'm using them all the time, and they're not all that buggy, 3 playthroughs in and no crashes related to them, and I think I understand most of the quirks on the user end. Who actually made that particular thing and does anyone know how it works and what controlls it?

I'm interested in digging into it a bit, and with what pohobos has done with traps and stuff it might be possible to even get the bugs out of them.
 
I'm glad to see "blind NPCs" shit bug finally fixed.

The setting for Mash's new fix isn't included too, because it's not been tested yet.
I'd perform all sorts of tests (I have many instances where this problem occurs), but can't due to lack of compatibility with Fallout.
 
sfall Arrays proposition

Am I the only one annoyed so much about how arrays work in sfall?

The problem is that there are 2 types of arrays:
1) "permanent" arrays which exist forever after they are created (unless implicitly freed), even between savegames (a bug in script code can lead to enormous save file size, and you can't easily know what arrays are "unused" to clean them out)
2) "temporary" arrays which exist for single frame and then deleted. They are useful in cases where you only need some small array in one function and don't want to bother about memory leaks. BUT, you can't use them in global script variable (which defined with "variable" keyword outside of procedure), which is really annoying.

HOWEVER, both array types are absolutely not something that regular programmer will understand as "arrays". By default, arrays in all other languages is a piece of information that is stored in memory. When you want array to be saved to file/savegame/somewhere else you usually use some kind of function for that. So you don't want "default" array type to be saved into savegames.
Temporary arrays are a bit different, because in many modern languages, there are things called ref counters, which can automatically free objects/arrays from memory after you don't need them (after last link is removed), but since we don't have such thing (and implementing one would be a pain), "temp_array" as it currently exist in sfall may be an option.

I was using a workaround for this problem in my own scripts:
- defined single procedure which creates permanent array and put it's ID in given sfall global variable
- I never use create_array directly, only use that procedure
But, it's not perfect. In some cases, when I need to pass my array between several scripts (like array of traps), this solution is ok (because I need to somehow pass variable ID between scripts and this is the only way since "imported" variables won't work with global/hook scripts). BUT, in other cases I only use array in one script.
Example:
- I have a list of some PIDs in mod's ini file.
- What I want to do is parse that list (text string) into an array of integers during script initialization (which happens after game load) and use that array efficiently throughout the lifespan of that script
- in this case I have to still store array and it's ID in savegame file, which is unnecessary, since I re-generate this array everytime and use it only in one script.
- what I want (and expect to be able) to do is use global script variable (not sfall global) like this:
Code:
variable pidList;

procedure start begin
  if (...) then begin
     pidList := create_array(10, 4); 
    // etc...
And not worry about savegames, because in real world arrays only automatically stored in memory.
In this case I don't need to worry about memory leak, because I will create this array only at script load, and I don't need to free it because it won't go to my savegame and will be freed from memory after game load.


I have a working implementation of third array type which don't automatically go into savegames in my current sfall build. But, there is several issues with that:
- To retain backward compatibility with older scripts, I will need to leave "create_array", "temp_array", "fix_array" functions as they were and add some kind of new methods. BUT, this will not fix the main problem with arrays (create_array will remain and will still be dangerous to use).
- I don't really want to add new opcodes to both sfall, compiler and decompiler, too...
- If my implementation will work differently from sfall master, I will have to apply my changes every time someone changes sfall
- While currently, RP don't use arrays at all, some other scripts might be using them in future and I will have a problem with compatibility.

So I propose to discuss how arrays would be implemented best to the point of including this into base sfall (if Timeslip approves). I can do sfall coding/compiling myself (since I already have working implementation).
My current (not final) proposed course of actions:
1) create_array will always create "normal" array (not temp and not permanent)
2) temp_array will still create arrays that delete themselves at the end of the frame (I'm not sure about this, but at least you can expect something like this when it's called "temp")
3) (maybe) fix_array will turn normal array into permanent. This is easy to implement, but more logical thing to do would be to add functions like "set_sfall_array" and "get_sfall_array" that would work similarly to "get_sfall_global_int" and "set_sfall_global" (you don't "turn" array into permanent, you just do a one-time operation of storing normal array in the global sfall arrays storage; and when you "get_sfall_array" it will create a copy of stored array as a normal sfall array)
4) All existing mods/scripts that use arrays will have to be changed/recompiled. I know, this sounds terrible, but as I looked, there are not many mods that use them (RP doesn't use them, and from all mods I've seen only my and Jim's mod used them).
5) I can also add a ddraw.ini setting that will allow switching between old and new array behavior (for backward compatibility), but for all new mods it will be recommended to use new mode.

Additional ideas about other aspects of arrays:
1) Currently, we can store values of different types in arrays, but the downside is: you have to define number of bytes for all array elements. While it's normal thing for C programmer to do, we are talking high level language here and this is an implementation detail. In other words, scripter doesn't need to be bothered by how many bytes his value takes in memory (unless he wants to, to work with binary files for example).
2) While having array dereferencing operator is cool (shortcut to get_array/set_array), we also need new syntax to define constant arrays. Like this:
Code:
array1 := {5, 7, 8, 1, 2};
Could be translated like so:
Code:
array1 := create_array(5);
set_array(array1, 0, 5);
set_array(array1, 1, 7);
set_array(array1, 2, 8);
set_array(array1, 3, 1);
set_array(array1, 4, 2);

3) We really need some kind of maps, objects or associative arrays (with numeric or string keys). While this can be easily done even with current arrays, there can be no readable shortcut for this. Best we can do now is something like:
Code:
ASSOC(array1, "key", "value");
but what would be readable is something like this:
Code:
array1["key"] := "value";
I imagine it might be done by adding new function "create_map" which would create just another array but with some flag in it, telling sfall that this is an associative array. It will be stored differently and when you use "set_array" it will check, if it's a map, allow index of any type and value.

I will think more about this and when I'll see the whole picture, I will implement it.
 
Last edited:
Unrelated bug report. ScriptExtender.cpp, StringSplit() function.
Code:
id=TempArray(count, maxlen);

This should be:
Code:
id=TempArray(count, maxlen+1);

Because maxlen is maximum string length after split, but you need 1 additional byte for null-termination. This bug caused several unstable problems with scripts.

Workaround function:
Code:
/**
 * Workaround for string_split bug in sfall 3.3
 */
procedure string_split_safe(variable str, variable split) begin
   variable lst;
   str += split;
   lst := string_split(str, split);
   resize_array(lst, len_array(lst) - 1);
   return lst;
end
 
Last edited:
Back
Top