Browse games

Browse games

My library

My library

My content

My content
My account
mod.io

Giving Everyone a Passive

Report guide
Share

Guide

In this guide, I will explain how to give every player character a Passive ability without modifying class progression tables. There are a few benefits to this technique:

  1. It doesn't overwrite a resource that might conflict with other mods.
  2. It will work with classes added by other mods without requiring a dependency.
  3. We can use a very similar technique to do some cool stuff with NPCs too.

However, if your mod is an overhaul of an existing class or if you only want to add a Passive to one or two specific classes, I'd recommend using the intended method (modifying class progression tables) instead of this technique.

So, what is the technique? It's a very simple Osiris script. If you don't understand Osiris, that's okay! All you need to do is copy some code and change a few names to be unique to your mod. And if you do want to learn Osiris, I hope this will be an easy way to get experience with a complete script. I won't define fundamental Osiris concepts because I want to keep this guide as simple as possible, but I will include optional sections that explain the basics of what the script is doing.

I will also not go into detail about how to create new Passives in this guide. You can find the lists of existing Passives in the Stats Editor, mostly under the Shared and SharedDev folders, in the Stats->Passive files.

Now let's get started!

Step 1: Create a Script

The first thing we need to do is create a file where we can write our Osiris script (called a goal). Open the Story Editor with one of the buttons above the game preview, highlighted in the image below. For more detail on using the Story Editor, see the Story Editor guide.

On the left side of the Story Editor window, right-click on one of the top-level scripts (such as _GLO_Analytics), and then select "Add New Item...". Do NOT add a new sub item.

This will prompt you to name the script. The name needs to be unique from every other game and mod script, so a good rule of thumb is to include an abbreviation of your username and your mod's name. This means the script name will have three parts:

  1. An indication of the script's purpose
  2. Your username abbreviation
  3. Your mod name abbreviation

Let's pick the first part of the name, which should give an idea about what the script will do. We want to give everyone a passive, so GivePassive is a short and descriptive name. Also, game scripts that affect everyone start with GLO_ (short for global), so we end up with GLO_GivePassive.

Next, pick abbreviations for your username and the mod's name. For example, I shorten my username "WorldWalker42" to WW. And, if the name of this mod was something like "Universal Passives", I would shorten that to UP.

By combining all three parts to get GLO_GivePassive_WW_UP, I'm very confident that this script name is unique and will not conflict with any other mod. My unique identifier for this mod, WW_UP, will be used several more times in the script, so for clarity I will replace it with IDENTIFIER from now on.

Every time you see IDENTIFIER, you'll need to replace it with what you've picked for your own mod. For example, the name of your script should be something like GLO_GivePassive_IDENTIFIER.

Step 2: Adding Rules

Now that we have a file for our script, let's actually write it! Double-click your script name in the list on the left side of the window and the file will open on the right side of the window. For now, there are just three empty text fields.

First, we need something to indicate when the script is just starting to run. We can do this in the top text field (the INIT section) by adding the following line:

DB_IDENTIFIER_Initialized(0);

Remember to replace IDENTIFIER with the unique identifier for your mod.

Now in the middle text field (the KB section), we add the following rules that will give players a Passive when the mod starts running or when they join the party:

IF
LevelLoaded(_)
AND
DB_IDENTIFIER_Initialized(0)
THEN
TimerLaunch("IDENTIFIER_InitDelay", 0);

IF
TimerFinished("IDENTIFIER_InitDelay")
THEN
NOT DB_IDENTIFIER_Initialized(0);
DB_IDENTIFIER_Initialized(1);

IF
DB_Players(_Player)
AND
DB_IDENTIFIER_Initialized(1)
AND
HasPassive(_Player, "DraconicAncestry_Red", 0)
THEN
AddPassive(_Player, "DraconicAncestry_Red");

And that's the whole script! You just need to replace every IDENTIFIER and also replace DraconicAncestry_Red with the Passive you want to give. Make sure to leave the quotation marks around the name of the Passive.

The final step is to open the "File" dropdown menu and choose "Generate Definitions, Build and Reload". Once it's done getting the script ready to run in the game, you can go test your mod, and every player character should now have the Passive.

Optional: Osiris Explanation

In this section, we'll talk about some of the mechanics of how the script works. If you aren't interested, feel free to skip to the next section!

First, the INIT section defines the fact 0 in the database DB_IDENTIFIER_Initialized. Because the INIT section is only executed once when the script starts running (which will be the first time a game is loaded with our mod) and 0 is often used to mean false, this fact indicates that the script is in an 'uninitialized' state. This doesn't mean anything beyond what we do with it, but as you'll see, it will be essential for us to give the Passive to preexisting characters.

Let's move on to the KB section. The first rule has two conditions:

  1. A level has just been loaded (such as when a save file is loaded or when moving between areas in the game)
  2. The fact 0 is in the database DB_IDENTIFIER_Initialized

Both of these conditions should always be true as soon as a newly modded save file is loaded, which will execute the rule's action. The action starts a timer named IDENTIFIER_InitDelay for 0 milliseconds, which will finish and trigger the TimerFinished event on the very next frame.

Why delay our script initialization by one frame? Because we're planning to access the database of players to give everyone a Passive, but Osiris executes scripts/goals in alphabetical order, and so whether you have access to DB_Players on the first frame depends on the location of your script/goal in the overall program/story. You can intentionally name your script something that will execute after the players become available and then remove the timer for a small efficiency boost, but for the sake of keeping this guide simple, I've opted to include the timer. By making the script wait until the second frame of our loaded game, we're guaranteed access to the players, no matter what the name of our script is.

Let's keep going. The second rule executes when the timer finishes, and all it does is replace the fact 0 with the fact 1 in the database DB_IDENTIFIER_Initialized. Just like 0 is often used to mean false, 1 is used to mean true. This indicates that our script has just gone from being uninitialized to being initialized, and any rule that has DB_IDENTIFIER_Initialized(1) as a condition will be triggered for evaluation. We can use this to trigger rules that will perform the setup we want.

The third rule does exactly this. It has three conditions:

  1. There is a player in the party for whom this rule has not executed (this condition will also trigger the rule whenever a new player is added to the party).
  2. The script is initialized (this condition will also trigger the rule when the script becomes initialized).
  3. The player does not already have the passive (which will never trigger the rule but does prevent it from trying to give players the Passive a second time if they leave and rejoin the party).

When the script starts running, the condition DB_IDENTIFIER_Initialized(1) will trigger this rule for evaluation and cause it to execute once for every player who is already in the party. From then on, the condition DB_Players(_Player) will trigger the rule again whenever a new player joins. The result is that everyone gets the Passive!

Giving the Passive at a Specific Level

You might want to give characters a passive only when they reach a certain level. We can do this with Osiris too, although it won't create a notification or appear in the level-up screen.

The setup for the script does not change. If your script already has the INIT section...

DB_IDENTIFIER_Initialized(0);

...and the first two rules of the KB section...

IF
LevelLoaded(_)
AND
DB_IDENTIFIER_Initialized(0)
THEN
TimerLaunch("IDENTIFIER_InitDelay", 0);

IF
TimerFinished("IDENTIFIER_InitDelay")
THEN
NOT DB_IDENTIFIER_Initialized(0);
DB_IDENTIFIER_Initialized(1);

...then you don't need to add them again. However, if you skipped Step 2 of this guide, you will need to include them now for the rest of the script to work.

Now we can get to the new rules. They're a little more complicated, but the only thing you need to do is still just replace IDENTIFIER with the one you picked for your mod in Step 1 and GiantKiller with the Passive you want.

IF
DB_Players(_Player)
AND
DB_IDENTIFIER_Initialized(1)
THEN
PROC_IDENTIFIER_GiveLeveledPassive(_Player);

IF
LeveledUp(_Player)
AND
DB_IDENTIFIER_Initialized(1)
THEN
PROC_IDENTIFIER_GiveLeveledPassive(_Player);

PROC
PROC_IDENTIFIER_GiveLeveledPassive((GUIDSTRING)_Player)
AND
HasPassive(_Player, "GiantKiller", 0)
AND
GetLevel(_Player, _Level)
AND
_Level >= 3
THEN
AddPassive(_Player, "GiantKiller");

That's it! Just remember to choose "Generate Definitions, Build and Reload" from the "File" dropdown before testing your mod.

Optional: Osiris Explanation

These rules are structured a little differently because now we need to give the Passive in any of these three events:

  1. The script starts running and there are already players at level 3+
  2. A character joins the party at level 3+
  3. A player levels up to 3+

Because we need to respond to more events, it's nice to be able to reuse Osiris logic. That's why we make a standalone procedure  PROC_IDENTIFIER_GiveLeveledPassive that decides whether a player is eligible for the Passive, and then all we have to do is call the procedure whenever a player might be eligible.

Notice how the first new rule looks very similar to the last rule in Step 2. Whenever a player joins the party, or when the script first starts running, it will call the procedure. If this player is at or above level 3, the procedure will give them the passive. That covers the first two events we need to worry about.

The second new rule covers the last event we need to worry about - a player leveling up. Whenever this happens after the script has been initialized (which should always be the case, but I like to check for it to make sure nothing went wrong), it will also call the procedure.

The procedure itself is very simple. It just makes sure the player doesn't already have the Passive and that they're at least level 3, and then gives them the Passive!

Targeting Other Kinds of Characters

We can do other fun things with similar Osiris rules. Let's say we want to give a certain category of NPCs a Passive, like buffing every guard in the game, or giving enemy Paladins a cool new ability.

We have to do this a little differently because the massive number of NPCs means that we don't have as convenient access to them as we do with player characters. Instead of looking for eligible characters as soon as the game loads, we have to wait for them to be involved in some sort of event. An easy event to wait for is the start of combat, because they probably won't use the passive before then anyway. Whenever combat starts, we can just look for characters involved with the fight who have the tag we care about, like GUARD or PALADIN.

We don't need any script setup to do this. All we need is a single rule in the KB section of a script:

IF
CombatStarted(_CombatGuid)
AND
DB_Is_InCombat(_Character, _CombatGuid)
AND
NOT DB_Players((CHARACTER)_Character)
AND
IsTagged((GUIDSTRING)_Character, (TAG)GUARD_0b52f35e-fb1f-4865-bcd2-5d21ef7343cd, 1)
AND
HasPassive(_Character, "DarkOnesBlessing", 0)
THEN
AddPassive(_Character, "DarkOnesBlessing");

All you need to change here is the Passive DarkOnesBlessing to the one you want to give (and remember to leave the quotation marks around the name), and also change the tag to the one you want.

Unfortunately, we can't just use the name of a tag (like GUARD), we need to use the tag's name and GUID (like GUARD_0b52f35e-fb1f-4865-bcd2-5d21ef7343cd). To find this, you can go to the Tag Editor by clicking the button directly to the right of the Story Editor button. Filter the results down to the name you want and then right-click on it to select "Copy as (TAG)TagUUID". Paste this into the script and you're good to go! There are tags for many different kinds of NPCs, all of the default classes, and much more.

Conclusion

That's it for now! There's so much that can be done with Osiris, and I hope this empowers you to make more of the mods you want. The script(s) discussed here can be expanded, customized, or made more efficient depending on your purpose and level of comfort with Osiris.

If you have a question or found a mistake in this guide, please leave a comment. Otherwise, happy modding!

Discussion
8 comments

Log in to join the discussion!
I want to be able to add a 'always advantage' on every roll but I have no idea which passive to call it or where to find the exact passive.
I personally would make a new passive to do this rather than using similar ones that are already in the game so that you have full control over it and it won't be affected by other mods. The details of making a new passive are beyond the scope of this guide, but generally speaking I would name the passive with a similar format as scripts (something like "IDENTIFIER_Description"), create a new Passive file in the Stats Editor section for your mod, and if needed search for how to do what you want using https://bg3.norbyte.dev For example, I searched "type:Passive advantage" and saw that "Tactical_Discipline" has the boost "Advantage(AllSavingThrows);Advantage(AllAbilities);" that you can put into the boost for your own passive.
What about adding multiple passives into the one passive? So I put a , in between or just post one after another?
You'd use a semicolon in between each passive, just like how the boosts "Advantage(AllSavingThrows)" and "Advantage(AllAbilities)" are separated by ";" in my first reply
Just wanted to make sure. I guessed the ; after I sent the ask
Interested party. Where can I get all the passive names etc.? I would like to make a mod that gives the monk class 4 ki points with every lvl up instead of the default value of one. And a mod that gives the Druid class -> subclass Circle of the Moon, with each lvl up, 2 more Wildshape Charges. How do I do that? Thank you
You can get the passive names in the Stats Editor. Most of the player passives are in the Shared and SharedDev folders in their Stats->Passive files, but there's loads more in the Gustav and GustavDev folders too. The built-in way to give more class resources with each level is to change the class progression tables in the Uuid Object Editor’s Shared and SharedDev Progressions->Progressions files, where you can see that the Boosts column uses the “ActionResource(resource,quantity,level)” function to increase these resources. However, I don’t know of a way to merge new values into progression tables, so I think you would need to override the progression table to change the amount of resources it gives, and this would limit your mod’s compatibility with others that override the same things. This isn’t necessarily a reason not to do it, but it’s something to consider. If it’s worth avoiding possible mod conflicts to you, it should be possible to create a passive or a stack of statuses that have Boosts to give extra resources for each level in the class. I tried a couple of things really quick and was getting weird behaviors that I don’t have the time to figure out, but there’s a “ClassLevelHigherOrEqualThan(level,’class’)” condition that you should be able to use with the ActionResource function to get something working. Once it is, you could give the passive/status to everyone tagged with the appropriate class tag as described in this guide.
Thank you for your time. It should be clear that changing the class progression in the class resource area is not compatible with other mods, or will be overwritten if it modifies the same resource. So since I've only been dealing with the mod topic and the toolkit accordingly for a few days, I'm facing a daunting task, even with such a seemingly simple mod, like turning one Ki point per level into 4/lvl up. Once I've understood what the process looks like, right up to the transfer into the game, then I could build on a foundation. At the moment it's all blindly wandering around in a maze and concocting something. Let's see if I can smooth out this bumpy road over time. Thanks for now. I'll have a look at the toolkit and try to get an overview somehow according to your description. Have a wonderful Christmas.
Last updated
100d
Reading time
11 min read
Views
1,180
Comments
8
Summary

A guide on how to give every player character a Passive without having to modify class progression tables. Other possibilities are discussed as well.

Author
WorldWalker42
WorldWalker42
Follow WorldWalker42

mod.io uses essential cookies to make our site work. With your consent, we may also use non-essential cookies to enhance your experience and understand how you interact with our services. The latter will be set only upon approval. or read our Cookies Policy.