Fallout 2 mod FO2 Engine Tweaks (Sfall)

Thanks for the updates!
Here are my compiles of SVN r263: (see my newest post in the thread for up-to-date version)
(The dll in "trace" folder is equal to the "debugging" one in modder's pack.)

BTW, the description related to inventory limit mode in ddraw.ini says:
";Add 8 to use the critters extra unused stat instead of for CritterInvSizeLimit for critters other than dude_obj"
But any number of CritterInvSizeLimitMode greater than 7 will be set to 0 in InventoryInit, or do I misunderstand something? :confused:
 
Last edited:
WOW, that's so awesome!! Thank you for the barter_mod function!! Now we can finally completely replace the pricing calculations of the vanilla! (this was the last show stopper)
When can we expect the next version? As I understand, I need new version of script compiler with new function supported, right?

May I make request about Script Editor included in sfall modderspack? It's awesome and all, but one bug really annoys me is how parser works. Very often when I add declaration of a new procedure, and before I add the definition (or when I'm in process of changing procedure arguments), the parser hangs the program completely (looks like he doesn't know what to do when one of the declarations doesn't meet exactly with definitions). Maybe some kind of try { } catch could solve this easily? (stopping the parser when it sees error instead of indefinetely trying to do something)
 
Last edited:
Thanks for the updates!
BTW, the description related to inventory limit mode in ddraw.ini says:
";Add 8 to use the critters extra unused stat instead of for CritterInvSizeLimit for critters other than dude_obj"
But any number of CritterInvSizeLimitMode greater than 7 will be set to 0 in InventoryInit, or do I misunderstand something? :confused:

Yes, as far as I can tell, the description in the ini has always been wrong, plus it referred to a feature that has never actually existed. And the code has always been bugged such that turning on the size limit for non-party members has never been possible... Here's the new description I added:
Code:
;These options modify the checks to see if a critter can carry an additional item, changing which items are counted towards the weight limit and adding an additional size check
;Set the mode to 0 to disable the size check, 1 to apply to pc only, 2 to apply to the pc and party members, or 3 to apply to all critters
;Only the PC uses CritterInvSizeLimit. Other critters will use the extra unused stat (STAT_unused = 10)
;Add 4 to the mode to limit the weight check to used items only

I'm not actually sure what'll happen if you use this new option and try to move an item from your inventory to your hands when it would take you over the weight limit... Probably should have checked that. >.>
 
Last edited:
I'm not actually sure what'll happen if you use this new option and try to move an item from your inventory to your hands when it would take you over the weight limit... Probably should have checked that. >.>
Like trying to put a 500 lb item from inventory on active slots in Mode 4?
Just did the test. With a 1000 lb Assault Rifle in my hands (Total WT displayed in red), I can still run around like nothing and shoot people, plus pick up stuff on the ground.
Now it's actually more like an unlimited carry weight cheat. :razz:
 
Last edited:
When can we expect the next version? As I understand, I need new version of script compiler with new function supported, right?
I've updated the modders pack with the new compiler. novarain seems to have already taken care of the dll. :)

Like trying to put a 500 lb item from inventory on active slots in Mode 4?
Just did the test. With a 1000 lb Assault Rifle in my hands (Total WT displayed in red), I can still run around like nothing and shoot people, plus pick up stuff on the ground.
Now it's actually more like an unlimited carry weight cheat. :razz:
Shame. I would have expected it to block you from running and picking more stuff up, if not to actually stop you putting it in your hands. Looks like I have a bit more work to do there. :p
 
I'm not actually sure what'll happen if you use this new option and try to move an item from your inventory to your hands when it would take you over the weight limit... Probably should have checked that. >.>
Like trying to put a 500 lb item from inventory on active slots in Mode 4?
Just did the test. With a 1000 lb Assault Rifle in my hands (Total WT displayed in red), I can still run around like nothing and shoot people, plus pick up stuff on the ground.
Now it's actually more like an unlimited carry weight cheat. :razz:

Just for what it's worth: I was hoping it'd work this way. Just wanted to introduce movement/AP/THC penalties; not make it impossible. It's just nice that it's now obvious why you're getting the penalties.
 
Just for what it's worth: I was hoping it'd work this way. Just wanted to introduce movement/AP/THC penalties; not make it impossible. It's just nice that it's now obvious why you're getting the penalties.
Sorry, I don't get it. In my test I don't seem to have any penalty.
Do you mean with your upcoming mod and mode 4 setting, I'll get the movement penalty even not in the combat?
 
Just for what it's worth: I was hoping it'd work this way. Just wanted to introduce movement/AP/THC penalties; not make it impossible. It's just nice that it's now obvious why you're getting the penalties.
Sorry, I don't get it. In my test I don't seem to have any penalty.
Do you mean with your upcoming mod and mode 4 setting, I'll get the movement penalty even not in the combat?

In my mod. Doesn't matter that you don't get the penalties outside of combat: it's not like unequiping your heavy armor and weapon before entering combat is a sensible tactic anyway. I really dislike the way the original carry weight system worked: it essentially just said to players that they shouldn't take low strength because they'd spend most of their time juggling equipment with their mules (and inexplicably not being able to trade using their items). Now I think it'll be more interesting: low strength isn't a question of more annoyance, but taking decisions based on what armor/weapons combination you can use (also, I no longer have the original system for min ST reqs for weapons, so that doesn't stack).
 
I'm interested, if there is some kind of in-depth guide (reference) for all of the SSL + sfall scripting language features?
For example, it would be cool to have a syntax sugar to define an array like this:
Code:
arr := [1, 2, 3, 6, 8];
basically doing this:
Code:
arr := temp_array(4, 5);
arr[0] := 1;
arr[1] := 2;
arr[2] := 3;
arr[3] := 6;
arr[4] := 8;

Another question, can you somehow define procedure with variable number of arguments? Like this:
Code:
procedure aaabbb(...) begin
   display_str("Arguments: "+arg[0]+", "+arg[1];
end

If Timeslip will ever read this: it would be great to have ability to define arrays that don't go to a savegame (like create_array) and don't get erased on every frame (like temp_array). This types of arrays are IMHO most useful, because they could've been defined in init of a global or a hook script and then used efficiently throughout the script lifetime, without worrying of savegame corruption (data leak). This is not a big issue, since we can use sfall_global to store array ID in, but it still feels wrong to store unnecessary data inside savegame (both sfall global and an array itself have nothing to do inside a savegame in many cases).

Another wish: when reading array index that doesn't exist, make some graceful exception (like returning 0 and writing to debug.log), instead of crashing the game with no explanation :)
 
Last edited:
@Timeslip, could you add this ammo formula (doesn't have to be as formula 6 of course)?

Code:
// Jim's Formula
static __declspec(naked) void DamageFunction6() {
    __asm {
        mov eax,dword ptr ds:[esi+0x8];        // Get pointer to critter's weapon
        call GetAmmoDivisor;            // Retrieve Ammo Divisor
        imul ebp,eax;                // Ammo Divisor = 1 * Ammo Divisor (ebp set to 1 earlier in function)
        mov ebx,dword ptr ss:[esp+0x1c];    // Get number of hits
        xor ecx,ecx;                // Set loop counter to zero
        test ebx,ebx;                // Is number of hits smaller than= 0?
        jle end;        // If yes, jump beyond damage calculation loop
ajmp:                            // Start of damage calculation loop
        mov edx,dword ptr ds:[esi+0x4];        // Get pointer to weapon (?)
        mov eax,dword ptr ds:[esi];        // Get pointer to critter (?)
        mov ebx,dword ptr ss:[esp+0x18];    // Get Bonus Ranged Damage
        call DamageFunctionSub1;        // Retrieve Raw Damage
        add ebx,eax;                 // Raw Damage = Raw Damage + Bonus Ranged Damage
        mov edx,dword ptr ss:[esp+0x28];    // Get armor DT
        mov eax,dword ptr ds:[esi+0x8];        // Get pointer to critter's weapon
        call GetAmmoDTMod;            // Retrieve ammo AM (Armor Modifier: adds or removes a percentage of the DT and DR)  
        cmp edx,eax;                // is ammo DT bigger than AM
        jge ijmp;                // If yes, go to end of calc because threshold not met
        mov eax,dword ptr ds:[esi+0x8];        // Get pointer to critter's weapon
        call GetAmmoDividend;            // Retrieve Ammo Dividend
        imul ebx,eax;                // Raw Damage = Raw Damage * Ammo Dividend
        test ebp,ebp;                // Is Ammo Divisor == 0?
        je djmp;                // If yes, avoid divide by zero error
        mov edx,ebx;
        mov eax,ebx;
        sar edx,0x1f;
        idiv ebp;
        mov ebx,eax;                // Otherwise, Raw Damage = Raw Damage / Ammo Divisor
djmp:
        mov edx,dword ptr ss:[esp+0x2c];    // Get armor DR
        mov eax,dword ptr ds:[esi+0x8];        // Get pointer to critter's weapon
        call GetAmmoDTMod;            // Retrieve ammo AM
        imul edx,eax;                // DR modifier = armor DR * ammo AM
        mov dword ptr ss:[esp+0x30],0x64;    //sets some variable to 100
        mov eax,edx;                //(not sure if I have to do this, but Haen does it)
        sar edx,0x1f;                // makes DR modifier the dividend
        idiv dword ptr ss:[esp+0x30];        // DR modifier = DR modifier / 100
        mov edx,dword ptr ss:[esp+0x2c];    // Get armor DR
        sub edx,eax;                // DR = DR - DR modifier (can be negative)
        test edx,edx;                // Is DR >= 0?
        jge gjmp;
        xor edx,edx;                // If no, set DR = 0
        jmp hjmp;
gjmp:
        cmp edx,0x64;                // Otherwise, is DR bigger than or equal to 100?
        jge ijmp;                // If yes, damage will be zero, so stop calculating and go to bottom of loop
hjmp:
        imul edx,ebx;                // Otherwise, Resisted Damage = DR * Raw Damage
        mov dword ptr ss:[esp+0x30],0x64;
        mov eax,edx;
        sar edx,0x1f;
        idiv dword ptr ss:[esp+0x30];        // Resisted Damage = Resisted Damage / 100
        sub ebx,eax;                // Raw Damage = Raw Damage - Resisted Damage
        test ebx,ebx;                // Is Raw Damage smaller than 0?
        jle ijmp;                // If yes, don't accumulate damage
        add dword ptr ds:[edi],ebx;        // Otherwise, Accumulated Damage = Accumulated Damage + Raw Damage
ijmp:
        mov eax,dword ptr ss:[esp+0x1c];    // Get number of hits
        inc ecx;                // counter += 1
        cmp ecx,eax;                // Is counter smaller than number of hits?
        jl ajmp;                // If yes, go back to start of damage calcuation loop (calculate damage for next hit)
end:
        jmp DamageFunctionReturn;        // Otherwise, exit loop
    }
}

Also, another request because of being spoiled: could you allow for disabling the hard-coded effects of cripplings (i.e. forced walking for crippled legs, unable to use 2-handed weapons with crippled arms)? I want to make different degress of crippled effects, that's why I ask.
 
Last edited by a moderator:
Hi Timeslip. Something seems wrong with the set_self sfall scripting function. I made a global variable (let's call it 800) and elsewhere stored a critter pid in it (let's say 16777311 for a random encounter trapper). Let's say I also added a text line 1500 ("I'm thinking of ") to obj_dude.msg. Then in obj_dude.int I wrote (as part of a larger clause of course):

op_set_self(op_global_var(800));
op_float_msg(op_dude_obj(), op_message_str(1, 1500) + op_obj_name(op_self_obj()), 5);

During gameplay the output text was:


I'm thinking of None
<none> <none>
However, when I used the standard (non-sfall scripting) function:

op_float_msg(op_dude_obj(), op_message_str(1, 1500) + op_proto_data(op_global_var(800), 1), 5);

I obtained the correct and expected output text:

I'm thinking of Trapper.

It's no big deal, as I said I found a way to accomplish what I wanted without set_self, but I thought you'd want to know about the issue.

Just for the sake of thoroughness, I'll mention that when I tried simply:

op_float_msg(op_dude_obj(), op_message_str(1, 1500) + op_obj_name(op_global_var(800)), 5);

I obtained the rather unexpected result:

I'm thinking of Critter
<critter><critter>

Thanks for all your hard work on sfall, keep up the great effort.</critter></critter></none></none>
 
Last edited:
The optimization in sslc is broken. Crazy side effects are observed like merging variables when they shouldn't be merged... It would be cool to be able to set optimize level in Script editor and inside sslc itself, don't merge variables or other crazy unstable stuff at optimize level 1 for example... I don't want to remove optimization altogether, there are useful features like removing unused procedures.

Edit: I think I've found a serious problem with list_as_array(LIST_CRITTERS) function.
I use code like this:
Code:
foreach crit in list_as_array(LIST_CRITTERS) begin
 ...
end

Now, in some cases, if I try to access "crit" directly (for example, doing debug_msg("crit: "+crit), game crashes). If I use tile_num(crit), game don't crash but script is failed with error "invalid argument to tile_num" in the logs.
If I wrap my loop with additional check like so:
Code:
foreach crit in list_as_array(LIST_CRITTERS) if (crit) then begin
 ...
end
It doesn't crash.
 
Last edited:
I was wondering, is it possible to refresh the graphics so as to force the AP counter to display the correct number (specifically, I want to have an option to spend AP's to aim, but can't find a way to have this represented graphically in the counter)? I tried force_graphics_refresh(true) but that's probably meant for something else.
 
@Timeslip, there seems to be a bug in the afterhitroll hookscript, the third return argument doesn't change the target, but the attacker strangely enough. If you use it in the intended way, the intended target simply attacks himself.
 
Last edited by a moderator:
My unofficial sfall compiles updated to SVN r263e (3.2.1.2634): (removed due to newer updates)
(The dll in "trace" folder is equal to the "debugging" one in modder's pack.)

Glovz updated his damage calculation to v4. The general process is still the same as v3, but now both amX & amY can be any positive integer rather than limited to maximum 9, and the bonus damage is only applied for unarmored (armDT=0 & armDR=0) targets.
 
Last edited:
@Timeslip, sorry, but I inconsiderately added my own version of the ddraw.dll (not the .ini) to my mod. If you want me to take it down I will of course. Is there a chance you could add the following as a separate ammo formula (it has a couple of small changes from the previous one)? I'm overriding Haen's formula currently...

Code:
// Jim's Formula
static __declspec(naked) void DamageFunction5() {
    __asm {
        mov eax,dword ptr ds:[esi+0x8];        // Get pointer to critter's weapon
        call GetAmmoDivisor;            // Retrieve Ammo Divisor
        imul ebp,eax;                // Ammo Divisor = 1 * Ammo Divisor (ebp set to 1 earlier in function)
        mov ebx,dword ptr ss:[esp+0x1c];    // Get number of hits
        xor ecx,ecx;                // Set loop counter to zero
        test ebx,ebx;                // Is number of hits smaller than= 0?
        jle end;        // If yes, jump beyond damage calculation loop
ajmp:                            // Start of damage calculation loop
        mov edx,dword ptr ds:[esi+0x4];        // Get pointer to weapon (?)
        mov eax,dword ptr ds:[esi];        // Get pointer to critter (?)
        call DamageFunctionSub1;        // Retrieve Raw Damage
        mov ebx,eax;                 // Move Raw Damage to ebx
        mov edx,dword ptr ss:[esp+0x28];    // Get armor DT
        mov eax,dword ptr ds:[esi+0x8];        // Get pointer to critter's weapon
        call GetAmmoDTMod;            // Retrieve ammo AM (Armor Modifier: adds or removes a percentage of the DT and DR)  
        cmp edx,eax;                // is ammo DT bigger than AM
        jge ijmp;                // If yes, go to end of calc because threshold not met
        mov edx,dword ptr ss:[esp+0x2c];    // Get armor DR
        mov eax,dword ptr ds:[esi+0x8];        // Get pointer to critter's weapon
        call GetAmmoDTMod;            // Retrieve ammo AM
        imul edx,eax;                // DR modifier = armor DR * ammo AM
        mov dword ptr ss:[esp+0x30],0x64;    //sets some variable to 100
        mov eax,edx;                //(not sure if I have to do this, but Haen does it)
        sar edx,0x1f;                // makes DR modifier the dividend
        idiv dword ptr ss:[esp+0x30];        // DR modifier = DR modifier / 100
        mov edx,dword ptr ss:[esp+0x2c];    // Get armor DR
        sub edx,eax;                // DR = DR - DR modifier (can be negative)
        test edx,edx;                // Is DR >= 0?
        jge gjmp;
        xor edx,edx;                // If no, set DR = 0
        jmp hjmp;
gjmp:
        cmp edx,0x64;                // Otherwise, is DR bigger than or equal to 100?
        jge ijmp;                // If yes, damage will be zero, so stop calculating and go to bottom of loop
hjmp:
        imul edx,ebx;                // Otherwise, Resisted Damage = DR * Raw Damage
        mov dword ptr ss:[esp+0x30],0x64;
        mov eax,edx;
        sar edx,0x1f;
        idiv dword ptr ss:[esp+0x30];        // Resisted Damage = Resisted Damage / 100
        sub ebx,eax;                // Raw Damage = Raw Damage - Resisted Damage
        test ebx,ebx;                // Is Raw Damage smaller than 0?
        jle ijmp;                // If yes, don't accumulate damage
        add dword ptr ds:[edi],ebx;        // Otherwise, Accumulated Damage = Accumulated Damage + Raw Damage
ijmp:
        mov eax,dword ptr ss:[esp+0x1c];    // Get number of hits
        inc ecx;                // counter += 1
        cmp ecx,eax;                // Is counter smaller than number of hits?
        jl ajmp;                // If yes, go back to start of damage calcuation loop (calculate damage for next hit)
end:
        jmp DamageFunctionReturn;        // Otherwise, exit loop
    }
}
 
Last edited by a moderator:
My unofficial sfall compiles updated to SVN r263f (3.2.1.2635): (removed due to newer updates)
(The DLLs in "trace" folders are equal to the "debugging" one in the modder's pack.)

Glovz's damage calculation fix got updated to v5. The general process is still the same as previous versions, but the code itself got overhauled for some serious optimizations and readability improvements.
He also added a version with his damage multiplier tweak: Critical Damage = Net Damage + (Net Damage * 25% * Critical Multiplier)
(In vanilla & Glovz's fix: Critical Damage = ND*CM/2)

I also added Jim's formula above as function 4. Now DamageFormula setting in sfall INI should be:
Code:
;Choose the damage formula used to calculate combat damage.
;Don't set this to anything other than 0 unless another mod you're using explicitly tells you to!
;0 - Fallout default
;1 - Glovz's Damage Fix
;2 - Glovz's Damage Fix with Damage Multiplier tweak
;4 - Jim's Formula
;5 - Haenlomal's Yet Another Ammo Mod.
DamageFormula=0
 
Last edited:
Okay, I apologize for my ignorance but how do I use any of this? I unzipped the mod pack into the Fallout 2 directory... what now?
 
I have a sfall related question: how would I go about measuring time in a global script? I want the script to subtract some HP from the player character every, say, 30 seconds. Should I use set_global_script_repeat? Or maybe there's some timer function I've missed?
I don't want to use the timed_event in the player's script, because it causes obscure bugs on saving/loading game.

Also, I've updated the request wiki with a bug report and a request.
Thanks in advance!
 
Back
Top