DynamicModifiers - COLLECTION_OWNER Limitations & Avoiding them

Gleb Bazov

Warlord
Joined
Feb 13, 2017
Messages
176
After doing some thinking and testing, I decided to approach the Modifiers/Requirements system from a different angle. Here is a brief outline of my findings and recommendations:

(1) the most limited of the DynamicModifiers (i.e. Core Modifiers / Modifier Types) are the ones that refer to COLLECTION_OWNER. The have a built-in recursion, such that the object that owns the Modifier applies the Modifier to itself.

The subject of a Modifier Type that refers to COLLECTION_OWNER is always the Modifier's owner itself. As a result, the Modifier/Requirements structure loses a great deal of flexibility in terms of structuring the required conditions. There is no second object to which a second Requirement can be applied. Both Requirement fields refer back to the owner object that applies the effect of the Modifier to itself.

For instance, the following DynamicModifiers:
<ModifierType>MODIFIER_SINGLE_CITY_GRANT_GREAT_PERSON_CLASS_IN_CITY</ModifierType>
<CollectionType>COLLECTION_OWNER</CollectionType>
<EffectType>EFFECT_GRANT_GREAT_PERSON_CLASS_IN_CITY</EffectType>

or

<ModifierType>MODIFIER_SINGLE_CITY_GRANT_BUILDING_IN_CITY</ModifierType>
<CollectionType>COLLECTION_OWNER</CollectionType>
<EffectType>EFFECT_GRANT_BUILDING_IN_CITY</EffectType>

and the like, are extremely inflexible.

For instance, relying solely on the first of these Modifiers, it is impossible to create a Civilization Trait that grants a GP in a player's city that has a specific district, once the player researches a certain technology. There is no way to put a Requirement on the player's research level as well as requirement that the city in question has a specific district (at least I've found no elegant way of doing this). In order to implement such a moderately more complex structure (Civilization Type, Technology Type and District Type Requirements), at least one and, more appropriately, two dummy buildings are required.

The same happens with trying to grant a specific building to every city of a specific civilization once a wonder is built using the MODIFIER_SINGLE_CITY_GRANT_BUILDING_IN_CITY. We are forced, instead, to use the not-quite-fitting MODIFIER_PLAYER_CITIES_GRANT_CHEAPEST_BUILDING_IN_CITY. Rather than defining a specific building type, we are stuck with the cheapest building -- something that is liable to change with any mod.

I am sure the solution has been obvious to many for some time, but I only now decided to spend some time working it out in my head, and so I thought I'd share. By the looks of some of the requests on this forum, there are some who may benefit from this short instruction.

The trick is to create a DynamicModifier that's suitable to your needs. However, doing it willy-nilly won't work. You need to think of the following first:

(1) What will be your OWNER -- what is the object that will confer the effects you want to introduce?

(2) What will be your SUBJECT -- what is the subject that will benefit from these effects?

(3) What will be your REQUIREMENTS -- the Owner & Subject Requirements.
Once you've worked that out, the first step is to devise a DynamicModifier - i.e. a core Modifier Type that will form the basis of your ultimate Modifier that gets attached to something in the game. For instance, if I want to:

(1) have a Civilization Trait;

(2) that generates a specific GP type;

(3) in a city that has a specific district;

(4) once the player researches a specific technology
I will have to first address the COLLECTION to which my Modifier Type applies. In this case, the Collection, to make it simple, will have to be PLAYER_CITIES. Why? Because the COLLECTION is the set of subjects of the Modifier I want to introduce. In the first examples above, the Modifier Types are recursive, they apply to the objects that own them. But, because I have at least two object types -- Civilization (Player) and City -- I have to break this recursion.

So, I would create something like this:

<ModifierType>MODIFIER_PLAYER_CITIES_GRANT_GP_IN_CITY</ModifierType>
<CollectionType>COLLECTION_PLAYER_CITIES</CollectionType>
<EffectType>EFFECT_GRANT_GREAT_PERSON_CLASS_IN_CITY</EffectType>

(and I also have to insert the new Modifier Type into Types:​

INSERT INTO Types (Type, Kind) VALUES
('MODIFIER_PLAYER_CITIES_GRANT_GP_IN_CITY', 'KIND_MODIFIER'),)​

As you can see, the two things that have changed are the moniker -- Modifier Type -- and the Collection Type. As a result, the new Modifier Type applies its Effect (the very same effect) to a different set of subjects. Also, importantly, there is a now a split between Owner and Subject of the Modifier.

The Owner can now be CIVILIZATION_X, while the Subject can be a City of CIVILIZATION_X. Accordingly, we can now use both OwnerRequirementSetId in parallel with SubjectRequirementSetId. We can safely require both of the following:

(1) that the player that holds the Trait/Modifier posess the relevant technology; and,
(using REQUIREMENT_PLAYER_HAS_TECHNOLOGY)​

(2) that the city of the player have a specific district;
(using REQUIREMENT_CITY_HAS_DISTRICT)
And, voila :)

ADDENDUM: An important consideration while you are creating a Dynamic Modifier is to check - is the Subject of your modifier capable of accepting the Effect you are seeking to apply? Is the Owner capable of carrying it?
 
Last edited:
Not a bad intro to creating dynamic modifiers, but if you want multiple types of requirements, I don't think you have to split them like that at all.

First off, I don't think the requirements are that specific, needing to be referencing the exact thing they should be. Like, you can attach a modifier to a unit or district with a collection of OWNER, but requirements like PLAYER_HAS_CIVIC and PLAYER_HAS_GOLDEN_AGE work just fine; they look at the player that owns the district/unit that the modifier is attached to. I just ran a test to confirm this, with a requirement of PLAYER_HAS_GOLDEN_AGE attached to a district with a COLLECTION_OWNER modifier, and it worked just fine as the Subject requirement set.

Second off, you can very easily combine multiple requirements into one set (not that I think you don't know this, but for anyone else reading it). When you make a Requirement Set, you can assign as many Requirements as you want to it in RequirementSetRequirements, I'm sure there's an upper limit, but I'm sure it's big enough to not limit any practical use. And, even when you need to, for example, check if one of a number of requirements holds up while also checking if all of another handful of requirements hold up, you can use a requirement of the type 'REQUIREMENT_REQUIREMENTSET_IS_MET', and define a second requirement set. I've done this, though I haven't tested if it works, setting my main requirementset (REQUIREMENTSET_TEST_ALL) to check 2 requirements, one of a REQUIREMENT_PLOT_RESOURCE_TAG_MATCHES type, and one of the above REQUIREMENTSET_IS_MET type, and then a second requirementset (REQUIREMENTSET_TEST_ANY) that checks if the plot has any of a number of improvements, like REQUIRES_PLOT_HAS_QUARRY.

So, in your above example where you have a Civilization Trait that generates a specific GP type in a city that has a specific district once the player researches a specific technology, you could literally just assign one requirementset, with separate requirements of types 'REQUIREMENT_CITY_HAS_DISTRICT' and 'REQUIREMENT_PLAYER_HAS_TECHNOLOGY', and voila. No need for laboriously checking and planning everything. Try it out, and if I'm wrong I'd love to know, because I'd have to redo a lot of my code.
 
Back
Top Bottom