Experiments on custom perks

Discussion in 'Fallout Tactics Modding' started by Melindil, May 25, 2018.

  1. Melindil

    Melindil First time out of the vault

    Apr 15, 2018
    I've been toying with the idea of what it would take to be able to have mods provide custom perks, since this is one of the areas that is pretty much hardcoded into the BOS.EXE.

    I was able to find the perk table in the EXE, which controls the minimum level, minimum stats/skills, and restricted/required races. This table also provides everything necessary for applying "simple" perks, which boost a single stat/skill. So modifying these aspects is not too difficult. However, I wanted to see if I could make behavioral changes to a new perk, as I had done with the fix for Team Player.

    To do this, I set up a basic extension engine, using a similar idea to the FT Improver project. A small edit to the EXE allows it to load my DLL, which can then make changes to the executable from inside the same process space. This allows 1) installing any other hex patches without needing to modify the EXE, and 2) adding hooks to "interesting" locations in the code, which can then fire off custom behavior. I then tied these hooks to a Lua interpreter inside the DLL.

    I then set about trying to create the following perk:

    Hulk Smash!
    Being radiated makes you very angry. Gain +2 Strength and +75 Radiation Resistance when in a radiated area.
    Ranks: 1
    Requirements: Level 16, EN 5, Doctor 50%

    The result is code similar to the following:

    Code:
    function OnStart ()
    
        logger:log("Entered OnStart")
    
        newperk = {name = "hulkSmash",
                   minlevel = 16,
                   maxperktaken = 1,
                   requiredstat1 = "doctor",
                   requiredamt1 = 50,
                   requiredEN = 5
                  }
        hookexecutor:ReplacePerk(newperk, 18)
    end
    The above adds the new entry to the perk table. This entry replaces perk #18, which has the internal name of "fortuneFinder", and is presently unused. Note that you'll want to add the appropriate strings to the localization and gui resources, so that the proper name, text, and image for the perk appear.

    I then added a hook for when an actor takes radiation damage:

    Code:
    function OnRadiated(e)
        logger:log("Radiated: " .. e["name"])
        if e:HasPerk("hulkSmash") then
          logger:log("Radiated and has perk: " .. e["name"])
          if e:GetTempPerkValue("hulkSmash") == 0 then
            logger:log(e["name"] .. " gains hulkSmash")
            e:DisplayMessage("<Cg>HULK SMASH!")
            bonus = {strength=2, radiationResist=75}
            e:ApplyTempBonus(bonus)
          end
          e:SetTempPerkValue("hulkSmash",6)    -- # of big ticks to keep buff
        end
    end
    Note that, internally, entities have both a "permanent" and "temporary" set of attributes. The code currently doesn't use the "temporary" copy of the perks or optional traits, so I can reuse those bytes to hold information, in this case a counter to set how long the applied bonus lasts.

    Finally, I need a way to turn the perk off at the right time. For this, I added a trigger to the "long" tick timer, which fires for each entity after 10 seconds (in real-time mode; turn-based mode adds 7 seconds to this timer for every complete turn):

    Code:
    function OnLongTick(e)
        curr = e:GetTempPerkValue("hulkSmash")
        if curr > 0 then
          curr = curr - 1
          if curr == 0 then
            logger:log(e["name"] .. " hulkSmash expired")
            e:DisplayMessage("Normal")
            bonus = {strength=2, radiationResist=75}
            e:RemoveTempBonus(bonus)
          end
          e:SetTempPerkValue("hulkSmash",curr)
        end
    end
    Now, to test it:

    fbos0008.jpg
    We use Rex, from Tutorial 1, as our guinea pig. First, cheat him up to the right level. Then, check to see if the perk can be applied:

    fbos0009.jpg
    Not yet - he has high enough level and EN, but doesn't have Doctor skill of 50%. After adding to that skill and reopening the perk list:

    fbos0010.jpg
    There it is. Now select it:

    fbos0011.jpg

    And walk over to the conveniently added radiation pit. After a few seconds:

    fbos0012.jpg

    Our message appears. And checking the character stats, the bonuses are applied:
    fbos0013.jpg
    Now, to test deactivation, we walk away from the radiation and wait a minute:

    fbos0014.jpg
    And the stats:

    fbos0015.jpg

    So it works!

    The engine isn't ready for actual use in a mod yet - it still needs a bit of error handling (right now, if there's an error, you're lucky if the Lua engine just fails to start; most of the time you end up with a crash). It will also need quite a few more trigger points to allow for more flexible custom perk behavior. But it's a good start as a proof-of-concept.

    I've posted the code for the DLL extender, and an installer to patch the BOS.EXE, to the following Github:

    https://github.com/melindil/FOTExtender

    (Up-front: Feel free to take the code, use it as a baseline for another project, mod, or otherwise.)
     
    • [Like] [Like] x 1
  2. nadeauhugo

    nadeauhugo Author of FOT mod THE SUM Modder

    Mar 9, 2014
    What? What? What? You are MY CHAMPION! :D I'll stay tuned for more updates about this prowess and will be one of your tester when I'll get back on the working table next month. Fantastic job here!
     
  3. nadeauhugo

    nadeauhugo Author of FOT mod THE SUM Modder

    Mar 9, 2014
    He I'm back to work on my mod! So I can't wait to see and try your Extender, and I'll try the Hex hacks in the next days. I have another question regarding perks : It is possible to modify or add perks, splendid. But could there be (eventually) a way, with the Extender, to control perks from the engine code? I mean, under certain circumstances, give a perk to the main player? They do that a lot in all the other Fallout (childkiller, grave digger, vault city inoculations, etc.), as easter eggs mostly, and this is a fantastic way to reward the player... Thanks!
     
  4. Melindil

    Melindil First time out of the vault

    Apr 15, 2018
    Yes, this will be possible. With the current code, it's almost possible to do a limited form of this already - just need to add one extra function for modifying permanent attributes (almost identical to adding temporary modifiers, just needs one offset change), and a trigger/hook for the condition which should apply the bonus perk. The one trigger that I haven't added yet, that's probably key, is to fire based on a mission or campaign variable being set. This would give at least one connection between the existing FoT script behaviors and the new extender behaviors. Being able to add new trigger conditions and actions is another thing I'm considering, but I don't know yet how difficult that would actually be, so I can't promise anything there yet.

    Recently, I've been focusing on getting the internal data structures figured out (primarily the Actor class). This would allow the scripting engine to see things like equipped weapons/armor, inventory, and so forth. One case I considered where this might be useful is in scripting an "intimidation" factor - e.g. have NPCs react differently based on how well-armed your character/squad is. (Might need a more thorough dialog system to make use of that - and that is on my to-do list to look into. :) )
     
  5. nadeauhugo

    nadeauhugo Author of FOT mod THE SUM Modder

    Mar 9, 2014
    Oh yeah, well done, and what a great to-do list you made for yourself. Happy to know that we will be able to connect scripts and triggers from variables. Almost everything works from them anyways. It seems an easy and pactical mean to walk this trough. Great job. I'll follow that in every step, thanks again!
     
  6. Imagination Engineer

    Imagination Engineer First time out of the vault

    Thursday
    Very good mod and news.
    (Somebody is a Hulk fan, lol!)