Fallout 2 mod Making turrets/bots lootable with sfall scripts

Discussion in 'Fallout General Modding' started by NovaRain, Apr 11, 2016.

  1. NovaRain

    NovaRain Casual Modder Modder Moderator

    Mar 10, 2007

    The standard/old school way is to modify their proto files (00000470.pro and 00000480.pro) and related scripts (ccturret, qcturret and wcturret). Using sfall global/hook scripts makes things simpler and is also more expandable, plus it's fun to make my own personal mini mod. :)


    1. Changing action flags in proto files with a global script:
    Code:
    // gl_loot_bots.ssl
    procedure start;
    #include ".\HEADERS\DEFINE.H"
    #include ".\HEADERS\define_extra.h"
    
    procedure start begin
        if(game_loaded) then begin
            set_global_script_repeat(60);
        end else begin
            // Auto-Cannon (for some reason its PID is not defined in CRITRPID.H)
            set_proto_data(16777696, PROTO_CR_ACTION_FLAGS, (CFLG_NODROP + CFLG_NOLIMBS + CFLG_NOAGES + CFLG_NOHEAL + CFLG_FLATTN + CFLG_NOKNOCKDOWN));
            // Gun Turret
            set_proto_data(PID_AUTO_GAT_GUN, PROTO_CR_ACTION_FLAGS, (CFLG_NODROP + CFLG_NOLIMBS + CFLG_NOAGES + CFLG_NOHEAL + CFLG_FLATTN + CFLG_NOKNOCKDOWN));
        end
    end
    
    Here's my half-a**ed explanation of those CFLG_* in set_proto_data. If you open their proto files in hex editor, it looks like this:


    The selected part contains the action flags for critters. From define_extra.h or the article on Vault-Tec Labs, the description of action flags is:
    Code:
    #define CFLG_BARTER             2  //0x00000002 - Barter (can trade with)
    #define CFLG_NOSTEAL           32  //0x00000020 - Steal (cannot steal from)
    #define CFLG_NODROP            64  //0x00000040 - Drop (doesn't drop items)
    #define CFLG_NOLIMBS          128  //0x00000080 - Limbs (cannot lose limbs)
    #define CFLG_NOAGES           256  //0x00000100 - Ages (dead body does not disappear)
    #define CFLG_NOHEAL           512  //0x00000200 - Heal (damage is not cured with time)
    #define CFLG_INVULN          1024  //0x00000400 - Invulnerable (cannot be hurt)
    #define CFLG_FLATTN          2048  //0x00000800 - Flatten (leaves no dead body)
    #define CFLG_SPECIAL         4096  //0x00001000 - Special (there is a special type of death)
    #define CFLG_RANGED          8192  //0x00002000 - Range (melee attack is possible at a distance)
    #define CFLG_NOKNOCKDOWN    16384  //0x00004000 - Knock (cannot be knocked down)
    The value 0x00004BE0 can be expressed as the sum of 0x00004000, 0x00000800, 0x00000200, 0x00000100, 0x00000080, 0x00000040 and 0x00000020. Which means Knock, Flatten, Heal, Ages, Limbs, Drop and Steal flags being set. To make turrets lootable, only Steal flag needs to be removed.
    The new value should be (0x00004000 + 0x00000800 + 0x00000200 + 0x00000100 + 0x00000080 + 0x00000040) = 0x00004BC0. But that's only necessary for hex-editing, with sfall scripting we only need to add up the flag variables and leave the rest to the compiler.
    (BTW, I hope Cubik2k's FO1/2 Critters Editor can be updated to let us edit those action flags and some other attributes.)


    2. Preventing Player from stealing turret weapons:

    Now turrets are stealable and lootable, but if you manage to steal from the turrets outside of Sierra Amy Depot or Navarro, you'll find that you can steal their Dual Minigun/Plasma Cannon. Because devs only put the weapon in their inventory not the left hand slot (you can't steal "equipped" items). There are several ways to prevent/fix this. One is editing the maps to put weapons in their left hand slots. Another is editing their scripts to make them automatically equip/wield weapons when you enter the maps, like the turrets on the Enclave Oil Rig. But I'm gonna take the other approach: making them unstealable while they're alive.

    sfall 3.5 added hs_useskill hook script, which runs when using any skill on any object. The logic is pretty simple here:
    Code:
    // hs_useskill.ssl
    procedure start;
    #include ".\HEADERS\DEFINE.H"
    #include ".\HEADERS\define_extra.h"
    
    procedure start begin
        variable user, target, skill;
        if not init_hook then begin
            user := get_sfall_arg;
            target := get_sfall_arg;
            skill := get_sfall_arg;
            if ((user == dude_obj) and (skill == SKILL_STEAL)) then begin
                if ((obj_pid(target) == 16777696) or (obj_pid(target) == PID_AUTO_GAT_GUN)) then begin
                    if not (is_critter_dead(target)) then begin
                        set_sfall_return(0);
                    end
                end
            end
        end
    end
    
    Any return values other than -1 will override the default engine handler, interrupting normal stealing action. PC will still perform the animations, but nothing will happen.


    3. Adding some reasonable loots on dead turrets and cleaning up their NPC-only items:

    Again, the standard/old school way is editing their scripts to add destroy_p_proc procedure, which will run when they get killed. Here we will do the same thing with only one script.

    sfall 1.46 added hs_ondeath hook script, which runs immediately after a critter dies for any reason. This one is a bit more complex than previous ones:
    Code:
    //hs_ondeath.ssl
    procedure start;
    #include ".\HEADERS\DEFINE.H"
    #include ".\HEADERS\define_extra.h"
    
    procedure start begin
        variable critter, removed_item, ammo, ammo_count;
    
        if not init_hook then begin
            critter := get_sfall_arg;
            // Auto-Cannon
            if (obj_pid(critter) == 16777696) then begin
                if (obj_is_carrying_obj_pid(critter, PID_DUAL_MINIGUN)) then begin
                    if (random(0, 1) == 1) then begin
                        ammo := create_object(PID_5MM_AP, 0, 0);
                        ammo_count := random(1, 2);
                        add_mult_objs_to_inven(critter, ammo, ammo_count);
                    end else begin
                        ammo := create_object(PID_5MM_JHP, 0, 0);
                        ammo_count := random(1, 2);
                        add_mult_objs_to_inven(critter, ammo, ammo_count);
                    end
                end
    
                if ((obj_is_carrying_obj_pid(critter, PID_HEAVY_DUAL_MINIGUN)) and (random(0, 1) == 1)) then begin
                    ammo := create_object(PID_223_FMJ, 0, 0);
                    ammo_count := random(1, 2);
                    add_mult_objs_to_inven(critter, ammo, ammo_count);
                end
    
                while ((obj_is_carrying_obj_pid(critter, PID_DUAL_MINIGUN)) or (obj_is_carrying_obj_pid(critter, PID_HEAVY_DUAL_MINIGUN))) do begin
                    removed_item := obj_carrying_pid_obj(critter, PID_DUAL_MINIGUN);
                    rm_obj_from_inven(critter, removed_item);
                    destroy_object(removed_item);
                    removed_item := obj_carrying_pid_obj(critter, PID_HEAVY_DUAL_MINIGUN);
                    rm_obj_from_inven(critter, removed_item);
                    destroy_object(removed_item);
                end
            end
    
            // Gun Turret
            if (obj_pid(critter) == PID_AUTO_GAT_GUN) then begin
                if (obj_is_carrying_obj_pid(critter, PID_GUN_TURRET_WEAPON) and (random(0 ,1) == 1)) then begin
                    add_obj_to_inven(critter, create_object(PID_MICRO_FUSION_CELL, 0, 0));
                end
    
                while (obj_is_carrying_obj_pid(critter, PID_GUN_TURRET_WEAPON)) do begin
                    removed_item := obj_carrying_pid_obj(critter, PID_GUN_TURRET_WEAPON);
                    rm_obj_from_inven(critter, removed_item);
                    destroy_object(removed_item);
                end
            end
        end
    end
    
    Using while loop to remove their weapons is probably unnecessary or overkill, because they only have one weapon in their inventory. I do it just in case.
    The turrets outside of Sierra Amy Depot will have 50% chance of dropping one or two boxes of 5mm JHP and 50% chance of dropping one or two boxes of 5mm AP.
    The turrets on the Enclave Oil Rig will have 50% chance of dropping one or two boxes of .223 FMJ.
    The turrets in Navarro base will have 50% chance of dropping a pack of Micro Fusion Cell.
    And no, you can't have their Daul Minigun, Heavy Dual Minigun or Dual Plasma Cannon.

    The three sfall scripts can be easily expanded to include sentry bots or other critters. Or you can add some checks against player's repair/science skill to let you strip usable weapons (actually just dropping some normal weapons on them). But currently I run into an interesting issue with checking their Robo Rocket Launcher.
     
    Last edited: Sep 22, 2017
    • [Like] [Like] x 2
  2. Darek

    Darek is currently unavailable

    Jan 7, 2008
    Nice example and explanation of some sfall scripting that I totally missed.:ok:
    I found it by searching for a way to edit NPCs skill stats. According to the devs notes and my testing "critter_mod_skill" only works for the dude, so was hoping it could be done with sfall. Do you know if there is a way?
    Also, in regards to your mod, I see that you can edit action flags, but what about the normal flags? If those can be edited, you could set the dual miniguns to "hidden item" and not have to worry that the player will ever lay their hands on them.
    Funny thing, I didn't know there was a hidden item flag until I accidentally found it today. How ever did I manage to miss that? :scratch:
     
  3. NovaRain

    NovaRain Casual Modder Modder Moderator

    Mar 10, 2007
    I haven't tried yet, but there are get/set_critter_skill_points sfall functions:
    Code:
    void set_critter_skill_points(int critter, int skill, int value)
    int  get_critter_skill_points(int critter, int skill)
    So that's why some NPC weapons just "vanish" when I enter the loot interface. I didn't notice it until now. :oops:
    Yes, it's possible to just add the "hidden item" flag to their photo files in memory. But I need to figure out why some weapons have different action/weapon flags. For example the normal minigun has "03" at 0x1A, which equals the sum of Big Gun (01) and 2Hand (02), but the Avenger Minigun has "A3" at 0x1A. Even if I add all action/weapon flags (01 + 02 + 08 + 10 + 80) it still doesn't match. :?

    EDIT: Also, it seems items with "hidden" flag can't be checked/manipulated with script functions. I tried to extend my scripts for sentry bots but couldn't check if they have Robo Rocket Launcher (a hidden item) in their inventory. This might make spawning appropriate ammo loot harder.
     
    Last edited: Jun 11, 2016
    • [Like] [Like] x 1
  4. .Pixote.

    .Pixote. Antediluvian as Feck
    Modder

    Sep 14, 2009
    Any chance that SFall could change the games critters HP and skills when you increase the combat difficulty in the game preferences screen? ATM I think the options only effect the players skills - wimpy - normal - rough. Wimpy gives the player a boost in skills, while rough reduces the players skills somewhat.
     
  5. Darek

    Darek is currently unavailable

    Jan 7, 2008
    Thanks, that is what I was looking for. For some reason when I glanced over sfall functions I thought those had to do with how many skill points you get when leveling up. They work fine but initially I had a bit trouble with the numbers adding up as I also used the normal "has_skill" function.
    The reason being the sfall functions reads/writes to the proto directly while "has_skill" gets bonuses added from stats such as agility and intelligence.

    The flags not matching has to do with the action flags. I'm pretty sure the difference is with weapons from Fallout 1 vs Fallout 2. I'm guessing the action flags where handled a bit different before. If you go into the mapper and re-set the action flags exactly the same way as they were before (ie look and pickup) on the minigun, you will find that the flag values now will match that of the avenger minigun.

    About the hidden flag setting, I haven't tested it at all myself. Just thought it could be useful, but if its hidden from the scripts too, maybe it's not in your case.

    Mmm, there are two difficulty switches on the preferences screen.
    Combat difficulty modifies enemies perception, likelihood to make targeted shots and their damage output. Game difficulty is the one that modifies skills (non-combat skills only). But yes I believe you can do that with sfall. You can check the game difficulty settings with "combat_difficulty" and "difficulty_level (values are 0,1 and 2), and then use the sfall functions that @NovaRain mentioned.
    something like:
    Code:
    If combat_difficulty ==2 then begin
        set_critter_skill_points(self_obj, 1, (get_critter_skill_points(self_obj, 1) -20));
    
    Basically reducing a NPCs Big guns skill if combat difficulty is set to "Rough"
     
    • [Like] [Like] x 1
  6. NovaRain

    NovaRain Casual Modder Modder Moderator

    Mar 10, 2007
    Oh, I got it, thanks. The "A" hex value should come from Look + PickUp flags. Since old items from FO1 also work without these two flags being set in their proto files, and you can't remove the two flags for items in the mapper, I'd guess the engine just treat all items (except containers) always having the two flags on.
     
    Last edited: Jun 12, 2016
  7. Daemonjax

    Daemonjax First time out of the vault

    19
    Jul 5, 2016
    Do you still plan to implement this?

    Do you think it would be possible to work around the limitation that hidden inventory items can't be manipulated with scripting by: unhiding it via sfall script function, then manipulating it with other scripts, and then hiding it again via sfall script function?

    EDIT: Mmm... but then how would we get the object ptr for it, right? Nevermind I guess (unless getting the pointer for it would work and doesn't count as manipulation).
     
    Last edited: Jul 16, 2016
  8. NovaRain

    NovaRain Casual Modder Modder Moderator

    Mar 10, 2007
    Sorry for the self-necro bump. I refined the mod to combine all scripts into one global script, and made eye bots lootable as well.
    Here's my mini mod with source included: http://www.mediafire.com/file/5g8mqt9gnlm4pvb/NR_lootable_bots.rar (requires sfall 3.5 or higher)

    Loots:
    • The turrets outside of Sierra Amy Depot will drop one or two boxes of 5mm JHP or AP.
    • The turrets on the Enclave Oil Rig have 50% chance of dropping one box of .223 FMJ.
    • The turrets in Navarro base have 50% chance of dropping a pack of Micro Fusion Cell.
    • Eye bots have 50% chance of dropping a pack of Small Energy Cell.
    • Sentry bots will drop one box of 5mm JHP or AP, and an Explosive Rocket or a Rocket AP.
     
    Last edited: Mar 23, 2018
    • [Like] [Like] x 2