Exclusive Groups
available in SPID 7.0.0+

Changelog

Spoiler:  
Show
  • Dec 6, 2024
  • Cleaned all the invisible characters that caused issues when trying to copy code examples.


Summary

Exclusive Groups define sets of distributable forms where only one from the set can be distributed at any time.
Ordering and other distribution rules are unaffected by Exclusive Group. The entry that is distributed first according to default ordering will prevent all other entries from the same Exclusive Group to be distributed to the same NPC.

Note, that Exclusive Groups also affect Linked Distribution and On Death Distribution.


Syntax

ExclusiveGroup = GroupName|FormsList
              required                             required                required
where:
  • ExclusiveGroup - a special key that define an Exclusive Group.
  • GroupName - any text that will be used as group's name. (separator | not allowed in the name)
  • FormsList* - a comma separated list of FormIDs or EditorIDs similar to default FormFilters in regular SPID entries. These forms will be added to the Exclusive Group.

*Combining modifier (+) doesn't make sense in FormsList, thus is not supported.


Examples

  • Defining Exclusive Group

ExclusiveGroup = Only One Sword|IronSword,SteelSword,DaedricSword
Now there will be an Exclusive Group named Only One Sword with 3 mutually exclusive swords.

  • Modifying existing Exclusive Group

You can also reference existing Exclusive Group by name and modify it by either adding or removing forms to it:
ExclusiveGroup = Only One Sword|SteelBattleaxe,-SteelSword
Only One Sword now doesn't contain SteelSword, but instead contains SteelBattleaxe.


When to use

Typical scenario when ExclusiveGroups could be helpful is when you find yourself creating tons of keywords just to ensure that you pick only one entry.

If you find the following setup familiar, you should adopt Exclusive Groups:

Keyword = GetsCoolSword|...|50
Keyword = GetsDecentAxe|-GetsCoolSword,...|50
Keyword = GetsOPBow|-GetsCoolSword,-GetsDecentAxe,...|50
; List goes on :)

Item = CoolSword|GetsCoolSword
Item = DecentAxe|GetsDecentAxe
Item = OPBow|GetsOPBow

Instead, you should be able to express your intent clearer and more efficiently:

Item = CoolSword|...|50
Item = DecentAxe|...|50
Item = OPBow|...|50

ExclusiveGroup = Primary Weapon|CoolSword,DecentAxe,OPBow

Article information

Added on

Edited on

Written by

sasnikol

36 comments

  1. megnoeu
    megnoeu
    • premium
    • 39 kudos
    I made a group as follows:

    ExclusiveGroup = myskinname|myWNAM1,myWNAM2,myWNAM3

    and tried to distribute them as below:

    Skin = myskinname|*dododo,*rerere,*mimimi|myracename

    But it doesn't seem to work. I want to distribute these skins to any NPC containing "dododo", "rerere", or "mimimi" in their Editor IDs who also are from race "myracename".

    The log says:

    (myskinname) FAIL - editorID doesn't exist
     
    It also reads that "Adding 'myskinname' exclusive group", followed by the corresponding ARMO records (myWNAM1,myWNAM2,myWNAM3)

    What does it mean? Which EDID is it referring to as absent? "myskinname"? But it's made as an ExclusiveGroup... Then how am I to distribute this group?

    I have SPID v7.2.0.RC11. What am I missing?
    1. sasnikol
      sasnikol
      • premium
      • 477 kudos
      Hey, thanks for commenting on a proper page!

      As for your question, ExclusiveGroup is not a Form by itself. It's just a place where you can tell SPID which forms you don't want to appear on the same NPC. I'm guessing what you want to achieve is this:

      ExclusiveGroup = CoolSkins|myWNAM1,myWNAM2,myWNAM3

      Keyword = DoReMi|*dododo,*rerere,*mimimi|myraceEDID

      Skin = myWNAM1|DoReMi|....|33
      Skin = myWNAM2|DoReMi|....|50
      Skin = myWNAM3|DoReMi|....|100

      A couple notes on the code above:

      • You still need to distribute each Skin, ExclusiveGroup doesn't distribute on its own
      • DoReMi keyword is just to organize the code to be a bit cleaner, you can place those filter directly in each Skin entry
      • Important part here is using random chances - if all entries have 100% only the myWNAM1 will ever appear, since it will be distributed first, and then ExclusiveGroup will prevent any other Skins from being distributed, so by giving a random chance, you allow SPID to sometimes skip Skins and try out those that are below.

      Hope that clarifies everything let me know if you'll have more questions.
    2. megnoeu
      megnoeu
      • premium
      • 39 kudos
      Oh my, this explains it. I misunderstood the concept of ExclusiveGroup then.

      But I think I'm facing another problem with template NPCs which I'm too darn tired to comprehend the tricks related to them with SPID. I'll give another chance later, haha!

      Thank you so much for your patience and your detailed explanation!
  2. OrrieL
    OrrieL
    • member
    • 0 kudos
    Does this work for spells? Cant make it work. Spells in the example are abilities (constant effect, self).
    Spell = 0x800~Myplugin.esp|ActorTypeNPC|NONE|NONE|NONE|NONE|33
    Spell = 0x801~Myplugin.esp|ActorTypeNPC|NONE|NONE|NONE|NONE|50
    Spell = 0x802~Myplugin.esp|ActorTypeNPC|NONE|NONE|NONE|NONE|100
    ExclusiveGroup = MySpells|0x800~Myplugin.esp,0x801~Myplugin.esp,0x802~Myplugin.esp
    SPID behaves like the ExclusiveGroup line was not in the config.
    1. sasnikol
      sasnikol
      • premium
      • 477 kudos
      Hm, does the log say anything?
    2. OrrieL
      OrrieL
      • member
      • 0 kudos
      Yes I can see from the log that the ExclusiveGroup was created with correct forms, but the spells are distributed like the ExclusiveGroup line was not in the ini at all. All the forms are distributed according to their chances, the 0x802 form is present on all ActorTypeNPC because it has 100% chance.
    3. sasnikol
      sasnikol
      • premium
      • 477 kudos
      Can you share the log? Sounds weird.
    4. OrrieL
      OrrieL
      • member
      • 0 kudos
      I have omitted some common lines to shorten the log and I have tried to add some abilities from skyrim.esm to avoid possible wrong edits on my abilities.
      [19:55:19:462] po3_SpellPerkItemDistributor v7.1.3.0
      [19:55:19:462] Game version : 1-5-97-0
      [19:55:20:115] *******************DEPENDENCIES*******************
      [19:55:20:115] powerofthree's Tweaks (po3_tweaks) detected : true
      [19:55:20:115] ***********************INI************************
      [19:55:20:163] 1 matching inis found
      [19:55:20:163] INI : Data\MySpells_DISTR.ini
      [19:55:20:165] **********************HOOKS***********************
      [19:55:20:166] Installed actor load hooks
      [19:55:20:184] **********************MERGES**********************
      [19:55:20:184] Failed to dispatch message to MergeMapper
      [19:55:20:184] INFO - MergeMapper not detected
      [19:56:03:713] ********************PROCESSING********************
      [19:56:03:713] Registered 3/3 Spells
      [19:56:03:713] *****************EXCLUSIVE GROUPS*****************
      [19:56:03:713] Adding 'MySpells' exclusive group
      [19:56:03:713]   [SPEL:000ED099]
      [19:56:03:713]   [SPEL:000ED09D]
      [19:56:03:713]   [SPEL:000ED09E]
      [19:56:03:714] **********************EVENTS**********************
      [19:56:03:714] Registered for struct RE::TESFormDeleteEvent
      [19:56:03:715] Registered class PCLevelMult::Manager
      [19:56:03:715] Registered for struct RE::TESDeathEvent
      [19:56:03:759] **************MAIN MENU DISTRIBUTION**************
      [19:56:03:759] Spell
      [19:56:03:759] [0xED099~Skyrim.esm] added to 509/2796 NPCs
      [19:56:03:759] [0xED09D~Skyrim.esm] added to 747/2796 NPCs
      [19:56:03:759] [0xED09E~Skyrim.esm] added to 1475/2796 NPCs
    5. sasnikol
      sasnikol
      • premium
      • 477 kudos
      But it appears to be working as intended if the exclusive group wouldn't work all npcs should be getting the third spell. Moreover, if you sum up all the distribution counts you'll see that they end up in roughly 2796. If you remove the ActorTypeNPC filter and test with only chances then those numbers should match perfercly.
    6. OrrieL
      OrrieL
      • member
      • 0 kudos
      This is the distribution if I remove the ActorTypeNPC keyword filter
      [21:14:15:489] [0xED099~Skyrim.esm] added to 948/2796 NPCs
      [21:14:15:489] [0xED09D~Skyrim.esm] added to 1382/2796 NPCs
      [21:14:15:489] [0xED09E~Skyrim.esm] added to 2796/2796 NPCs
      0xED09E Form was added to every actor, that means that there is at least one actor that have more than one of the forms which is not exclusive.
      This is the log when I remove the ExclusiveGroup line.
      [21:18:06:996] [0xED099~Skyrim.esm] added to 930/2796 NPCs
      [21:18:06:996] [0xED09D~Skyrim.esm] added to 1391/2796 NPCs
      [21:18:06:996] [0xED09E~Skyrim.esm] added to 2796/2796 NPCs
      I am probably missing something if you are saying its working as intended.

      EDIT: The distributions are basically the same if we take randomness into accout, thats why I am saying that SPID is behaving like the ExclusiveGroup line was not defined.
      EDIT2: If I use keywords in the ExclusiveGroup then it distributes the keywords uniformly 33/33/33%
    7. sasnikol
      sasnikol
      • premium
      • 477 kudos
      Hmm, interesting, sounds like the condition that checks for existing spells does not work properly, can you try using -0xED099 in form filters on 3d spell to see if it would make any difference.
    8. OrrieL
      OrrieL
      • member
      • 0 kudos
      Spell = 0xED099~Skyrim.esm|NONE|NONE|NONE|NONE|NONE|33
      Spell = 0xED09E~Skyrim.esm|NONE|-0xED099|NONE|NONE|NONE|100

      [0xED099~Skyrim.esm] added to 892/2796 NPC
      [0xED09E~Skyrim.esm] added to 2796/2796 NPCs
    9. sasnikol
      sasnikol
      • premium
      • 477 kudos
      okay, then it's for sure spells filtering has not been working at all
    10. OrrieL
      OrrieL
      • member
      • 0 kudos
      Yes, thank you for your time, I guess you will pass that info to po3 for possible to fix.
    11. sasnikol
      sasnikol
      • premium
      • 477 kudos
      I've looked into the issue and confirmed the problem. I don't have ETA for the fix at this time, as I think this would be fix with the rework that I plan to do soon-ish.

      If you're curious why it happened, it's because SPID doesn't actually add spells one-by-one, but instead it collects all the spells that should be distributed to given NPC and after that adds them all at once. This was done for performance reasons, but what this means is that when other spell distribution's filter tries to check previously distributed spell it looks for spells that NPC already has, and at this point in time NPC has none of the distributed spells yet, hence all the filters/ExclusiveGroups essentially don't see other spells.
  3. Bectile
    Bectile
    • premium
    • 89 kudos
    Hi, I had a question. I am trying to distribute some rare fancy skins I made to roosters, and the log seems to indicate that it is working, but when I spawn a bunch (50) at my location, they are unaffected. Is that supposed to be that way? I am trying to convert my mod from using the dynamic animal variants apply_skin spell to using a straight skin swap, it seems so much cleaner, and easier to customize.
    Basically I have:
    Skin = rooster1||mihailcock_race||||10
    Skin = rooster2||mihailcock_race||||15
    Skin = rooster3||mihailcock_race||||15
    ExclusiveGroup = rooster1,rooster2,rooster3

    and when I check the log, the group is correct and a few of each skin are said to be distributed. But their skins aren't being changed when I spawn a bunch via console. With the old method which uses a distributed spell to apply the skin, they would wear their new skins even when spawned. Would assigning a keyword in an exclusive group and then distributing the proper skin to the proper keywork make any difference? Or just make it messier. :D

    Thank you so much for your advice!

    EDIT: I think I see what I was getting wrong. The skins aren't random per NPC rooster: if the skin is distributed to one of the base formids of a rooster then *all* of the roosters with that base formid will have that skin. I just happened to be spawning the baseid that didn't get distributed to. I guess I still need the skin changer spell to truly randomize them. :/  (I was also playing around with Stray Dog skins and each time I entered the game, all the stray dogs I spawned would be the same skin, but different each login, helped me to understand what was going on)

    I was kind of hoping this could be something similar to Base Object Swapper, but I misunderstood the mechanics. Sorry to trouble you!
    1. sasnikol
      sasnikol
      • premium
      • 477 kudos
      Hey, yeah. I think having a spell attached to an actor allows it to affect only a single reference. The thing is when you spawn a bunch of the same NPC that is not templated/leveled you actually get just to instances of the same NPC. And SPID modifies the base NPC of an Actor. If said dogs would be setup through leveled list or a templated dog, from which all other dogs would derive, then SPID-based randomization would work. But I assume you're looking for a way to do that without touching NPCs.

      Another option is to use SPID to distribute the spell this way you'll have the best of both worlds: flexible filtering of SPID and per-actor randomization.

      EDIT: Actually, you know what I'll take a look into this behavior. The actor has a skin, so I probably could look up the code to see where the game takes that skin from and put it there instead.
    2. Bectile
      Bectile
      • premium
      • 89 kudos
      Ah yes SPID is distributing the skinchanger spell to all roosters/dogs, I just wanted to see if I could simplify the process. And if I had been able to achieve it, it would have been cool to be able to allow people to edit actual chances for each skin to appear, instead of it being a complete random dice roll as it is now.

      One thing that sparked my interest was an auto-strip area that altered my stray dog companion. The way the spell works is by giving the animal a random skin outfit to wear, which can technically be removed by either the unequip console command or by such scripts that make you naked when bathing, etc. Having an actual skin assigned seemed better in general, it wouldn't be removeable. Plus I'm looking into applying size differences and being able to have a linked spell to certain skins seemed like a cool way to do it.

      Another thing I was trying to see if I could get to work is I have a mod that uses that spell to distribute horker skins, and someone wanted a patch so the skin of their carcass from one of those hunting mods would match the skin of the animal they killed. I thought maybe I could achieve that by having SPID assign a keyword based on what outfit they are wearing, and then make textures to apply based on that keyword, but unfortunately that did not work either, it didn't recognize the ones added by the spell. The only keywords were assigned to animals who were given the skins in a patch.  I think it may be due to the order of distribution, since keywords are assigned before spells?

      Thanks again for taking the time to reply <3
    3. sasnikol
      sasnikol
      • premium
      • 477 kudos
      There is a lot going on for you I'd be glad to help you and explore how we could extend SPID to facilitate your goal. Ideally removing the need for spells, since they do seem like a workaround in this case
    4. Bectile
      Bectile
      • premium
      • 89 kudos
      I really appreciate your willingness to look into it and possibly expand its capabilities, thank you!!
    5. sasnikol
      sasnikol
      • premium
      • 477 kudos
      I made a note in my list to look into it now that I finally was able to catch the crash that people were talking about, I think I’ll be able to finish the 7.2.0 and work on new stuff
  4. shyvana6300
    shyvana6300
    • member
    • 0 kudos
    I've read the guide but i'm still confuse about the syntax. Do i need to declare a custom keyword or custom name for each item before declare Exclusive group?
    If you don't mind please create an Exclusive group for these item below for me to understand:

    Item = 0x801~Kemper's Weapon Collection II.esp|ActorTypeNPC,ActorTypeDragon,ActorTypeGiant|-Child,-Citizen|NONE|NONE|1|1
    ;Bejeweled Lance
    Item = 0x802~Kemper's Weapon Collection II.esp|ActorTypeNPC,ActorTypeDragon,ActorTypeGiant|-Child,-Citizen|NONE|NONE|1|1
    ;Triple Skull Mace
    Item = 0x803~Kemper's Weapon Collection II.esp|ActorTypeNPC,ActorTypeDragon,ActorTypeGiant|-Child,-Citizen|NONE|NONE|1|1
    1. sasnikol
      sasnikol
      • premium
      • 477 kudos
      You can declare exclusive group at any point in the file, they'll always find any valid referenced forms. Even if you didn't distribute those, SPID will check if an NPC already has one of the listed forms.

      In your case the group is this:
      ExclusiveGroup = MyItems|0x801~Kemper's Weapon Collection II.esp,0x802~Kemper's Weapon Collection II.esp,0x803~Kemper's Weapon Collection II.esp
    2. shyvana6300
      shyvana6300
      • member
      • 0 kudos
      i understand now, thank you very much!
  5. huhwhat23921
    huhwhat23921
    • member
    • 38 kudos
    I can't figure out what i'm doing wrong.
    Expectations: Mihail's Skeleton Colossus, is both a Draugr and a Skeleton type. It should receive only one of either perks below.
    Result: It received both perks

    Perk = BonyPerk||SkeletonFaction|NONE|NONE|NONE
    Perk = FleshyPerk||DraugrFaction|NONE|NONE|NONE|NONE
    Exclusivegroup = MihailColossusPickOne|BonyPerk,FleshyPerk
    1. sasnikol
      sasnikol
      • premium
      • 477 kudos
      The left side of each entry is case sensitive it should’ve been ExclusiveGroup. I’m not sure but SPID should’ve logged this problem. If not I’ll add it.

      Also, all trailing NONEs can be omitted.
    2. huhwhat23921
      huhwhat23921
      • member
      • 38 kudos
      Thank you for the tips :-) I can see in the logs the exclusive groups do get created after i fixed the typo.
      I couldn't get exclusion groups to work with perks somehow, i had better success using keywords for exclusion groups, then distributing perks to those keywords.
    3. sasnikol
      sasnikol
      • premium
      • 477 kudos
      Can you share what you tried and the config with keywords? Exclusive groups should work.
  6. Sranger
    Sranger
    • premium
    • 189 kudos

    i think there's a bug with exclusive groups, in my SPID file I have 4 different exclusive groups for keywords.
    in the log file it says they're all being processed, but I notice that the keywords in some of the groups aren't consistently being applied.

    for example:

    Keyword = keyword_a|-custom_keyword|||-C||33
    Keyword = keyword_b|-custom_keyword|||-C||34
    Keyword = keyword_c|-custom_keyword|||-C||33
    ExclusiveGroup = My Group|keyword_a,keyword_b,keyword_c


    My understanding is this should be uniformly applied to every NPC that does not have the custom_keyword, where everyone has either keyword_a, keyword_b, or keyword_c since the chances all add up to 100 (33 + 34 +33), as defined since it is an ExclusiveGroup.

    However, during testing I will notice that not all the NPCs have a keyword applied from the group.

    In fact, when I look at the logs, i see this:

    [21:10:54:272] Keyword_a [0xF43~my_plugin.esp] added to 894/2738 NPCs
    [21:10:54:272] Keyword_b [0xF44~my_plugin.esp] added to 582/2738 NPCs
    [21:10:54:272] Keyword_c [0xF45~my_plugin.esp] added to 378/2738 NPCs

    The total here does not add up to even close to the total amount of NPCs,. I know i have a trait filter -C that excludes children, but theres no way 1851/2738 are excluding just children lol
    1. sasnikol
      sasnikol
      • premium
      • 477 kudos
      My understanding is this should be uniformly applied to every NPC
      this one is what confused you. Unfortunately, SPID doesn't provide uniform distribution at the moment. keyword_b has a 34% out of 67% cases where keyword_a wasn't given. Then keyword_c has 33% chance in cases when previous both were not given. This is not specific to Exclusive Groups, but rather to how chances work in general in SPID.

      So your config actually has the following probabilities:
      Pa = 33%
      Pb = (100 - 33)% * 34% = 67% * 34% = 22.78%
      Pc = 67% * (100 - 34)% * 33% = 14.5926%
      P0 = 67% * 66% * 67% = 29.6274%
      which can be confirmed by the numbers in log output. (P0 - chance where actually none of 3 would be given, which explains why number in the log don't add up to the total NPCs count)

      What you want to do is:
      Pa = 33%
      Pb = 50% (this will make 67% * 50% to give 33.5% probability overall)
      Pc = 100% (to cover the rest 67% * (100 - 50)% * 100% = 33.5%
    2. Sranger
      Sranger
      • premium
      • 189 kudos
      I see.  The documentation needs to be fixed then because in the exclusive group article, the chances all add up to 100 with 50, 40, 10 in the example
    3. sasnikol
      sasnikol
      • premium
      • 477 kudos
      ah, that wasn't meant to represent that those chances are related. I'll tweak the chances so that their sum isn't 100% to not give the wrong impression. Note, that Exclusive Groups do not change any base SPID behavior.
    4. Sranger
      Sranger
      • premium
      • 189 kudos
      So in this example:
      Item = CoolSword|...|33
      Item = DecentAxe|...|50
      Item = OPBow|...|
      ExclusiveGroup = Primary Weapon|CoolSword,DecentAxe,OPBow


      What determines what is evaluated first in the exclusive group? Because I want coolsword to get 33% distribution, and then decent axe to be half of 67%, and the rest to be OPBow.

      But that's not really what I'm observing.
    5. sasnikol
      sasnikol
      • premium
      • 477 kudos
      Yes, this is how it should work. Exclusive groups are not “evaluated” per se, all entries are processed in exactly the same order as without such group. Group only ensures that only one of those entries will be added.
  7. LuciusPortanius24
    LuciusPortanius24
    • member
    • 37 kudos


    If you find the following setup familiar, you should adopt Exclusive Groups:

    Keyword = GetsCoolSword|...|50
    Keyword = GetsDecentAxe|-GetsCoolSword,...|40
    Keyword = GetsOPBow|-GetsCoolSword,-GetsDecentAxe,...|10




    I feel seen :D

    Thanks for this great update & explainer!
    1. sasnikol
      sasnikol
      • premium
      • 477 kudos
      ha-ha yes, we need to tone down our usage of keywords, this should greatly both simplify readability of configs as well as performance of the actual filtering, since it won't need to do multiple redundant checks