• We have updated our Community Code of Conduct. Please read through the new rules for the forum that are an integral part of Paradox Interactive’s User Agreement.

Spurius89

Recruit
Jul 9, 2019
4
0
Hey everyone,

I've been on a quest to find an answer to a modding dilemma that has been puzzling me for quite some time. Despite my extensive research, I haven't been able to find a solution, so I'm hoping someone out there can help shed some light on the matter.

Here's the scenario: I've developed a system of six traits within my mod. The traits are as follows: God, FirstAngel, SecondAngel, Devil, FirstDemon, and SecondDemon. What I'm aiming to achieve is a mechanism where, if the holder of the God or Devil trait dies or is killed, or if there is no one left possessing those traits, the FirstAngel or FirstDemon will automatically assume the role of God or Devil, respectively. Additionally, the new FirstAngel or FirstDemon will be chosen from the pool of SecondAngel or SecondDemon traits. Furthermore, the SecondAngel or SecondDemon trait should become available to be acquired by random individuals who possess the traits of brave or possessed.

In essence, I want to ensure that at any given time, only one individual possesses the complete set of all six traits I've created, akin to the concept of Augustus Trait. The trigger for this transition should occur only when the current holder of the six traits dies.

Now, my question is whether it is possible to develop a trait system that will automatically initiate this chain of events as described. I'm open to any suggestions or insights you may have regarding this matter.

Thank you in advance for your assistance, and I look forward to hearing your thoughts on this perplexing modding challenge.



namespace = angels_events

# Event 1: Acquiring the God trait from the FirstAngel trait
angels_events.0001 = {
type = character_event
title = angels_events.0001.t
desc = "The power of the divine flows through the realms, seeking a new vessel. With the passing of the God, the chosen FirstAngel emerges as the rightful heir. The divine essence is bestowed upon the new holder, replacing their once-held FirstAngel trait."

trigger = {
OR = {
has_died = yes
killer = { always = yes }
NOT = { exists = trait:God }
}
has_trait = FirstAngel
}

immediate = {
add_trait = God
remove_trait = FirstAngel
}
}

# Event 2: Acquiring the FirstAngel trait from the SecondAngel trait
angels_events.0002 = {
type = character_event
title = angels_events.0002.t
desc = "The celestial hierarchy shifts as the holder of the SecondAngel trait passes from this world. The divine order decrees that the worthy successor shall ascend to the rank of the FirstAngel, relinquishing their previous SecondAngel status."

trigger = {
OR = {
has_died = yes
killer = { always = yes }
NOT = { exists = trait:FirstAngel }
}
has_trait = SecondAngel
}

immediate = {
add_trait = FirstAngel
remove_trait = SecondAngel
}
}

# Event 3: Selecting a random holder of the Brave trait as the new SecondAngel
angels_events.0003 = {
type = character_event
title = angels_events.0003.t
desc = "The celestial forces yearn for balance as the SecondAngel relinquishes their ethereal mantle. The fates turn to the brave souls among them, bestowing the esteemed title of the SecondAngel upon one of them."

trigger = {
OR = {
has_died = yes
killer = { always = yes }
NOT = { exists = trait:SecondAngel }
}
has_trait = Brave
}

immediate = {
random_ruler = yes
add_trait = SecondAngel
remove_trait = Brave
}
}

# Event 4: Ensuring only one holder of each trait at a time
angels_events.0004 = {
type = character_event
title = angels_events.0004.t
desc = "The celestial order mandates that the divine traits of God, FirstAngel, and SecondAngel should never converge within a single individual. Should such an imbalance occur, the universe corrects itself, bestowing the rightful titles to the chosen ones."

trigger = {
OR = {
has_trait = { trait:God trait:FirstAngel trait:SecondAngel }
count_holders_of_trait = { trait:God value = 2 }
count_holders_of_trait = { trait:FirstAngel value = 2 }
count_holders_of_trait = { trait:SecondAngel value = 2 }
}
}

immediate = {
remove_trait = { trait:God trait:FirstAngel trait:SecondAngel }
}
}

# Event 5: Triggered when one of the trait holders dies or no one is alive
angels_events.0005 = {
type = character_event
title = angels_events.0005.t
desc = "The celestial balance shatters as the divine essence fades from the world. With the death of one of the blessed trait holders or the absence of any remaining, the celestial forces convulse, eagerly seeking new conduits for their sacred powers."

trigger = {
OR = {
has_died = yes
NOT = { exists = trait:God }
NOT = { exists = trait:FirstAngel }
NOT = { exists = trait:SecondAngel }
}
}

immediate = {
trigger_event = { id = angels_events.0001 id = angels_events.0002 id = angels_events.0003 }
}
}
 
So there's a few errors, but I think also you're coming at this the wrong way. In CK3, there are on_actions, some which get triggered from the script, and some which get triggered from the game's code. One of the game's on_actions that triggers from code is on_death. This triggers everytime a character dies in the game, so I would leverage that to do what you want. You can still send events if you want, but this is how you would trigger the trait change, and the sending of the events. has_died isn't a trigger that the game recognizes, so this is how you have to do stuff on the death of a character.

So you'll want to create an on_action file and put something like the following in it (tweak to your own needs):

Code:
on_death = { # We can use the on_death on action to call a custom on_action of our own
    on_actions = {
        my_mod_on_action # This is our custom on_action
    }
}

my_mod_on_action = { # Same as above
    effect = {

        # If the character dies with God trait, do this
        if = {
            limit = { has_trait = god_trait }
          
            # Save the scope for localization (and I think it looks nicer)
            save_scope_as = old_god
            
            # Find the first angel character and save their scope
            random_living_character = {
                limit = {
                    has_trait = first_angel_trait
                }
                save_scope_as = new_god
            }
            
            # Find the second angel character and save their scope
            random_living_character = {
                limit = {
                    has_trait = second_angel_trait
                }
                save_scope_as = new_first_angel
            }
            
            # Find a new character to be second_angel
            random_living_character = {
                limit = {
                    NOT = {
                        has_trait = first_angel_trait
                        has_trait = second_angel_trait
                    }
                    OR = {
                        has_trait = brave
                        has_trait = possessed
                    }
                    # Add any other restrictions here -- gender, prowess, etc.
                }
                save_scope_as = new_second_angel
            }
            
            # We don't need to go into this scope when this dead character is the root,
            # but it looks nicer, imo
            scope:old_god = {
                remove_trait = god_trait
            }
            
            # Change new_god's traits
            scope:new_god = {
                remove_trait = first_angel_trait
                add_trait = god_trait
            }
            
            # Change new_first_angel's traits
            scope:new_first_angel = {
                remove_trait = second_angel_trait
                add_trait = first_angel_trait
            }
            
            # Change new_second_angel's traits
            scope:new_second_angel = {
                add_trait = second_angel_trait
            }           
            
            # Send an event to every player to inform them what's happened
            every_player = {
                trigger_event = {
                    id = angels_event.0001
                }
            }
        }
      
        # If the character with first_angel_trait dies, do this
        if = {
            limit = { has_trait = first_angel_trait }
            
            # Save the scope for localization (and I think it looks nicer)
            save_scope_as = old_first_angel
            
            # Find the second angel character and save their scope
            random_living_character = {
                limit = {
                    has_trait = second_angel_trait
                }
                save_scope_as = new_first_angel
            }
            
            # Find a new character to be second_angel
            random_living_character = {
                limit = {
                    NOT = {
                        has_trait = first_angel_trait
                        has_trait = second_angel_trait
                    }
                    OR = {
                        has_trait = brave
                        has_trait = possessed
                    }
                    # Add any other restrictions here -- gender, prowess, etc.
                }
                save_scope_as = new_second_angel
            }
            
            # We don't need to go into this scope when this dead character is the root,
            # but it looks nicer, imo
            scope:new_first_angel = {
                remove_trait = second_angel_trait
                add_trait = first_angel_trait
            }
            
            # Change new_second_angel's traits
            scope:new_second_angel = {
                add_trait = second_angel_trait
            }           
            
            # Send an event to every player to inform them what's happened
            every_player = {
                trigger_event = {
                    id = angels_event.0002
                }
            }
        }
       # If the character with second_angel_trait dies, do this
        if = {
            limit = { has_trait = first_angel_trait }
            
            # Save the scope for localization (and I think it looks nicer)
            save_scope_as = old_second_angel
            
            # Find a new character to be second_angel
            random_living_character = {
                limit = {
                    NOT = {
                        has_trait = first_angel_trait
                        has_trait = second_angel_trait
                    }
                    OR = {
                        has_trait = brave
                        has_trait = possessed
                    }
                    # Add any other restrictions here -- gender, prowess, etc.
                }
                save_scope_as = new_second_angel
            }
            
            # We don't need to go into this scope when this dead character is the root,
            # but it looks nicer, imo
            scope:new_second_angel = {
                add_trait = second_angel_trait
            }           
            
            # Send an event to every player to inform them what's happened
            every_player = {
                trigger_event = {
                    id = angels_event.0003
                }
            }
        }
    }
    # Repeat the above for the devil/demon variations
}

# Event example: Do similar for other variations
angels_event.0001 = {
    type = character_event
    title = angels_event.0001.t
    desc = "The power of the divine flows through the realms, seeking a new vessel. With the passing of the God, the chosen FirstAngel emerges as the rightful heir. The divine essence is bestowed upon the new holder, replacing their once-held FirstAngel trait."
    left_portrait = scope:new_god

    immediate = {
        # Though it's already assigned, we use show_as_tooltip to show the player that
        # it happened (this won't assign the traits twice, only show them in the tooltip)
        show_as_tooltip = {
            scope:new_god = {
                add_trait = god_trait
            }
        }
        show_as_tooltip = {
            scope:new_first_angel = {
                add_trait = first_angel_trait
            }
        }
        show_as_tooltip = {
            scope:new_first_angel = {
                add_trait = second_angel_trait
            }
        }
    }

    option = {
        name = "OK"
    }
}

This will make sure that whenever a character with one of these traits dies, their trait gets passed on to the next person. However, this requires that you have these traits assigned at the beginning of the game. You can either do this by manually writing in the traits into a character in the character files, or you can use another on_action called on_game_start (or on_game_start_after_lobby) to randomly assign these traits to any characters in the game, based on whatever criteria you decide.

If you want to see the triggers and effects that are defined in the game you can find them on the Wiki, but you can also go into the effects.log and triggers.log files found in C:\Users\YourName\Documents\Paradox Interactive\Crusader Kings III\logs

Hope that's helpful and not too overwhelming. Best of luck!
 
Yeah, you can give someone a trait via console, then test if the on_action works by killing them via console or debug interaction, either typing in kill [character id] or by right-clicking on them and using the debug interaction menu's 'Slay Character!' interaction.

2023-07-15 11-57-53 - debug character id.png


The character ID is under the pink DEBUG when you hover over a character's portrait. So in this case, to kill this character, I'd type kill 18010 (don't use Historical ID, just ID).

Based on the script, I would start with second_angeL_trait. Give that to a character, then kill them, and the game should hopefully find someone to replace them. The script should only trigger when a character with that trait dies (note that I just wrote in an approximate for what to name the trait--you should replace second_angel_trait, etc. with what you actually called the trait in your own file).

And when you create a new on_action file, make sure that it is saved in 'UTF-8 with BOM.' If you're using Notepad, when you go to save the file, in the bottom right of the save file window you can change the format from UTF-8 and should make it UTF-8 with BOM (the game needs it to be this format to read the files properly).
 
I tried everything ,

i using notepad++ , inchange the coding from utf8 to uto8 with bom.

I open the game

i put someone with brave trait , and other character with Second Angel Trait. And other with first angel trait and God trait.

Then i slain them from The one with God Trait down until second angel trait.
Yet still the one with have brave trait. Doesnt still have the second angel trait.
 
I'm new to modding, but I'm having issues with getting my event to trigger another.

If I do event myRival.11001, and select option #2, it triggers 11001. If I do event myRival.11002, it also triggers 11001 for some reason.

My code in 11001 looks like:


namespace = myRivalry
myRivalry.11001 = {
...
option = {
name = rivalry.11001.b
add_prestige = minor_prestige_gain
stress_impact = {
shy = medium_stress_gain
}
trigger_event = myRivalry.11002
}

}

Then:

myRivalry.11002 = {
type = character_event
title = rivalry.11002.t
...
no trigger listed
}
...
}
I've tried a bunch of stuff to get this to work:
- Checking the encoding on the file to be UTF-8 BOM.
- Tried adding a scope for the triggering character and passing that along
- Using the trigger_event = { id = { myRivalry.11002 } }

But nothing seems to be working. Any help would be appreciated.
 
Last edited:
I'm new to modding, but I'm having issues with getting my event to trigger another.

If I do event myRival.11001, and select option #2, it triggers 11001. If I do event myRival.11002, it also triggers 11001 for some reason.

My code in 11001 looks like:



I've tried a bunch of stuff to get this to work:
- Checking the encoding on the file to be UTF-8 BOM.
- Tried adding a scope for the triggering character and passing that along
- Using the trigger_event = { id = { myRivalry.11002 } }

But nothing seems to be working. Any help would be appreciated.
It's hard to say based on this. At a glance, this makes sense to me. If you upload the full event file to a reply I'll take a look at it for you.

I've previously had weird bugs where, because I broke something somewhere else in the file, events would randomly fire on me. Mostly, when that happens, it's namespace related (and I don't know if namespace is case sensitive, or if it even reads case, but that could be something to look at, if changing the namespace to something like my_rival or myrival affects it), but I'm not sure in this case.
 
  • 1
Reactions:
Thanks for be willing to take a look, here's the file. I'll try to also see if changing the capitalization affects anything with it
 

Attachments

  • my_rival_event.txt
    3,9 KB · Views: 0
  • 1Like
  • 1
Reactions:
Thanks for be willing to take a look, here's the file. I'll try to also see if changing the capitalization affects anything with it
Well, I learned something cool today: if you have a five-digit or greater number in the event ID, it breaks the event (I also learned that event IDs are case sensitive, so double cool). I replaced the event ids with one less zero (e.g., myRivalry.1101), and they started working as expected.

There's a few minor errors (like having written target: and has_activity not existing as a trigger), but when I only replaced the event ID numbers, everything fired as expected.
 
  • 1
  • 1Like
Reactions: