• We are currently performing site maintenance, parts of civfanatics are currently offline, but will come back online in the coming days (this includes any time you see the message "account suspended"). For more updates please see here.

Game Plot Yield Modifier Only Working When the Plot is Owned

Red Key

Modder
Joined
Sep 24, 2011
Messages
424
Location
USA
I am trying to make food harder to come by in tundra, so that food only exists in certain circumstances. My code below works sort of, but the game only seems to adjust the plot yields when they are within a player's borders. Unowned plots show the original unmodified yield and it is only when the plot becomes owned that the correct yield is shown. This really bugs me and I would like the correct yield to be shown even when the plot is unowned. Anyone know if that is possible? I have also tried some other ways of doing it, but this way seems the most likely to work since it is a general "game modifier" that I expect to operate on all plots rather than a player or city plot yield modifier.

Right now I am only checking for tundra and freshwater, but I made two requirement sets so I could easily add more conditions later to the "TEST_ANY" set.

Code:
INSERT INTO GameModifiers (ModifierId) VALUES ('RK_TUNDRA_DYNAMIC_FOOD');
INSERT INTO Modifiers (ModifierId, ModifierType, SubjectRequirementSetId) VALUES ('RK_TUNDRA_DYNAMIC_FOOD', 'MODIFIER_GAME_ADJUST_PLOT_YIELD', 'RK_TUNDRA_FOOD_REQUIREMENTS');
INSERT INTO ModifierArguments (ModifierId, Name, Value) VALUES ('RK_TUNDRA_DYNAMIC_FOOD', 'YieldType', 'YIELD_FOOD');
INSERT INTO ModifierArguments (ModifierId, Name, Value) VALUES ('RK_TUNDRA_DYNAMIC_FOOD', 'Amount', 1);
INSERT INTO RequirementSets (RequirementSetId, RequirementSetType) VALUES 
('RK_TUNDRA_FOOD_REQUIREMENTS', 'REQUIREMENTSET_TEST_ALL'),
('RK_TUNDRA_FOOD_PLOT_REQUIREMENTS', 'REQUIREMENTSET_TEST_ANY');
INSERT INTO RequirementSetRequirements (RequirementSetId, RequirementId) VALUES
('RK_TUNDRA_FOOD_REQUIREMENTS', 'REQUIRES_PLOT_HAS_TUNDRA'),
('RK_TUNDRA_FOOD_REQUIREMENTS', 'RK_TUNDRA_FOOD_PLOT_REQUIREMENTS_MET'),
('RK_TUNDRA_FOOD_PLOT_REQUIREMENTS', 'REQUIRES_PLOT_IS_FRESH_WATER');
INSERT INTO Requirements (RequirementId, RequirementType) VALUES
('RK_TUNDRA_FOOD_PLOT_REQUIREMENTS_MET', 'REQUIREMENT_REQUIREMENTSET_IS_MET');
INSERT INTO RequirementArguments (RequirementId, Name, Value) VALUES
('RK_TUNDRA_FOOD_PLOT_REQUIREMENTS_MET', 'RequirementSetId', 'RK_TUNDRA_FOOD_PLOT_REQUIREMENTS');
 
I don't believe you will be able to get the modifier to work any differently so far as the UI showing the values on unowned plots.

I could be wrong about this of course, but I think the issue is not so much the plot yields themselves as it is the UI tooltip code.
 
Last edited:
I am trying to make food harder to come by in tundra, so that food only exists in certain circumstances.
I suppose, you use the above code together with a statement like that?
Code:
UPDATE Terrain_YieldChanges SET YieldChange=0
WHERE YieldType="YIELD_FOOD" AND (TerrainType="TERRAIN_TUNDRA" OR TerrainType="TERRAIN_TUNDRA_HILLS");


For the general visibility of the correct yield even when the modified plot is unowned you could try to change the yield not directly, but by applying a Food feature like FEATURE_MARSH. I don't know whether that can be modified via SQL.

In a Lua script (gameplay context) you can run over the entire map and use Plot:IsFreshWater() & Plot:GetTerrainType() to check and if appropriate set eg. marsh with TerrainBuilder.SetFeatureType(pPlot, eFeatureType)

.
 
Thanks for the replies. I was hoping I just missed something that was somehow making my code only work for player plots. If the problem is in the UI or DLL itself then I will just abandon this idea. I was exploring this as an update to my Key Terrain Balancing mod that is already on the Steam workshop, so I will just leave that mod as it is now.

I suppose, you use the above code together with a statement like that?

Yes I did not paste all the code because the other parts do not impact the part that is not working. I do have a statement like that to reduce food yield to 0 and I was also boosting tundra and tundra hills production by 1. Adding a feature to the plots is beyond what I want to do since features also change other things besides the food yield.
 
I do have a statement like that to reduce food yield to 0 and I was also boosting tundra and tundra hills production by 1.
I had just a close look, because I'm toying around a similar idea (in case the food reduced mines are too dry on large plain/tundra areas): adjacent to rivers: some marsh/wheat on flatlands & woods on "naked" hills

.
 
In the opening post this code was given for all players:
Code:
INSERT INTO GameModifiers (ModifierId) VALUES ('RK_TUNDRA_DYNAMIC_FOOD');

INSERT INTO Modifiers (ModifierId, ModifierType, SubjectRequirementSetId)
VALUES ('RK_TUNDRA_DYNAMIC_FOOD', 'MODIFIER_GAME_ADJUST_PLOT_YIELD', 'RK_TUNDRA_FOOD_REQUIREMENTS');

If now the code shall be only applied to the Human player, must the ModifierType be changed to MODIFIER_PLAYER_ADJUST_PLOT_YIELD or remain MODIFIER_GAME_ADJUST_PLOT_YIELD?
Code:
INSERT INTO GameModifiers (ModifierId) VALUES ('RK_TUNDRA_DYNAMIC_FOOD');

INSERT INTO Modifiers (ModifierId, ModifierType, OwnerRequirementSetId, SubjectRequirementSetId)
VALUES ('RK_TUNDRA_DYNAMIC_FOOD', 'MODIFIER_PLAYER_ADJUST_PLOT_YIELD', 'PLAYER_IS_HUMAN', 'RK_TUNDRA_FOOD_REQUIREMENTS');

.
 
Yes it should be -- or at least I would. The behavior with the plot data will remain the same, though. The effect will not be seen in the UI until the player owns the plot.

You could also use the TraitModifiers table instead of the GameModifiers table and attach the modifier to the "default" Major Civ Leader Trait TRAIT_LEADER_MAJOR_CIV
 
  • Like
Reactions: cvb
The effect will not be seen in the UI until the player owns the plot. [...] Major Civ Leader Trait TRAIT_LEADER_MAJOR_CIV
Yeah, while watching a RUSSIA gameplay video it was strange to see a difference between the tiles Peter already owned and the ones he was going to own soon.

For the Requirements I want to use TerrainType & ResourceType, so I searched for a table containing both and chose then Resource_ValidTerrains. Does it call for problems when fetching a ("any") table, which may be defined for an entire different purpose? (Is this valid at all?)
Code:
INSERT INTO RequirementArguments (RequirementId, Name, Value)
VALUES ("RESOURCE_REQUIREMENT_JJ", "ResourceType", SELECT ResourceType FROM Resource_ValidTerrains
                                                   WHERE TerrainType IN ("TERRAIN_PLAINS", "TERRAIN_PLAINS_HILLS", "TERRAIN_TUNDRA", "TERRAIN_TUNDRA_HILLS")
                                                   AND ResourceType = "RESOURCE_DEER");
 
You would not I think want to do such a thing since it will return at least two rows from table Resource_ValidTerrains with the result that you would be attempting to do as if you had just directly coded this:
Code:
INSERT INTO RequirementArguments (RequirementId, Name, Value)
VALUES ("RESOURCE_REQUIREMENT_JJ", "ResourceType", "RESOURCE_DEER"),
 ("RESOURCE_REQUIREMENT_JJ", "ResourceType", "RESOURCE_DEER");
Which will cause a UniqueConstraint fatal syntax error, and the entirety of your code chunk I would expect to fail because of the violation of the Uniqueness Requirements. You cannot have two or more rows in table RequirementArguments with the same "RequirementId" and "Name" arguments.

It's better to just code the Deer requirement directly as
Code:
INSERT INTO RequirementArguments (RequirementId, Name, Value)
VALUES ('RESOURCE_REQUIREMENT_JJ', 'ResourceType', 'RESOURCE_DEER');
You would want to create second or third requirements attached to the RequirmeentSet to deal with the terrain issues. Remember that Requirements can specify that the conditions of an entirely separate RequirmeentSet must be met, and in that separated RequirementSet you can use a _TEST_ANY and add requirements to this set for each of the Terrain Types you want to use. Also bear in mind that in the unmodded game these are the only two rows referenced to "RESOURCE_DEER" in table "Resource_ValidTerrains"
Code:
ResourceType	TerrainType
RESOURCE_DEER	TERRAIN_TUNDRA
RESOURCE_DEER	TERRAIN_TUNDRA_HILLS
Table <Resource_ValidFeatures> also specifies that "RESOURCE_DEER" can appear on any Forest tile regardless of underlying terrain. So if you want your modifier to only take effect on Deer tiles that are bare of Forests you will need another Requirement somewhere in the mix that uses an "Inverse" for the plot has to have "FEATURE_FOREST".
 
  • Like
Reactions: cvb
With regard to the OP & visibility of the modification in the UI an approach via Lua & features/resources (Marsh, Wheat) would give the possibility to depend the +1Food to the plot on the surrounding plots: check first 1, 2 or perhaps 3 adjacent rings for already existing amount of food.
----
it will return at least two rows from table Resource_ValidTerrains with the result that you would [...] cause a UniqueConstraint fatal syntax error, and the entirety of your code chunk I would expect to fail because of the violation of the Uniqueness Requirements. You cannot have two or more rows in table RequirementArguments with the same "RequirementId" and "Name" arguments.
Printed out and attached to wall beyond desktop ...

Yes, the Deer can be on every TUNDRA and FOREST, which in turn means nearly all (land) terrain (even modded forest on snow). So I try to insert some terrainRequirement to be sure it contains at least 1 food, because in case of the mentioned snowHillsForestDeer (noFood, 3prod) an attempted food reduction may result actually in an increment, because the sign of -1 may be ignored and +1 used instead.

I have to go back two steps first anyway, so here are the mines again:
Code:
INSERT INTO ImprovementModifiers (ImprovementType, ModifierId)
VALUES ("IMPROVEMENT_MINE", "MACERATE_MINE_JJ");

INSERT INTO Modifiers (ModifierId, ModifierType, OwnerRequirementSetId, SubjectRequirementSetId)
VALUES ("MACERATE_MINE_JJ", "MODIFIER_SINGLE_PLOT_ADJUST_PLOT_YIELDS", "PLAYER_IS_HUMAN", "PLOT_HAS_REQUIREMENTS_JJ");

INSERT INTO ModifierArguments (ModifierId, Name, Value)
VALUES ("MACERATE_MINE_JJ", "Amount", -1),
       ("MACERATE_MINE_JJ", "YieldType", "YIELD_FOOD");

INSERT INTO RequirementSets (RequirementSetId, RequirementSetType)
VALUES ("PLOT_HAS_REQUIREMENTS_JJ", "REQUIREMENTSET_TEST_ANY");

INSERT INTO RequirementSetRequirements (RequirementSetId, RequirementId)
VALUES ("PLOT_HAS_REQUIREMENTS_JJ", "PLOT_IS_GRASS_HILLS_TERRAIN_REQUIREMENT"),
       ("PLOT_HAS_REQUIREMENTS_JJ", "PLOT_IS_PLAINS_HILLS_TERRAIN_REQUIREMENT"),
       ("PLOT_HAS_REQUIREMENTS_JJ", "PLOT_IS_TUNDRA_HILLS_TERRAIN_REQUIREMENT"),
       ("PLOT_HAS_REQUIREMENTS_JJ", "PLOT_IS_GRASS_JJ"),
       ("PLOT_HAS_REQUIREMENTS_JJ", "PLOT_IS_PLAINS_JJ"),
       ("PLOT_HAS_REQUIREMENTS_JJ", "PLOT_IS_TUNDRA_JJ");

INSERT INTO Requirements (RequirementId, RequirementType)
VALUES ("PLOT_IS_GRASS_JJ", "REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES"),
       ("PLOT_IS_PLAINS_JJ", "REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES"),
       ("PLOT_IS_TUNDRA_JJ", "REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES");

INSERT INTO RequirementArguments (RequirementId, Name, Value)
VALUES ("PLOT_IS_GRASS_JJ", "TerrainType", "TERRAIN_GRASS"),
       ("PLOT_IS_PLAINS_JJ", "TerrainType", "TERRAIN_PLAINS"),
       ("PLOT_IS_TUNDRA_JJ", "TerrainType", "TERRAIN_TUNDRA");
It feels a bit obfuscatory, that PLOT_IS_XXXXX_HILLS_TERRAIN_REQUIREMENT is defined by Firaxis, but PLOT_IS_XXXXX_TERRAIN_REQUIREMENT is not?!?

.
 
A Few of these may be stemming from mods
Code:
RequirementId	RequirementType
PETRA_YIELD_MODIFIER_REQUIRES_PLOT_HAS_DESERT	REQUIREMENT_PLOT_TERRAIN_CLASS_MATCHES
MACHU_PICCHU_MODIFIER_REQUIRES_PLOT_HAS_SNOW	REQUIREMENT_PLOT_TERRAIN_CLASS_MATCHES
MACHU_PICCHU_MODIFIER_REQUIRES_PLOT_HAS_TUNDRA	REQUIREMENT_PLOT_TERRAIN_CLASS_MATCHES
REQUIRES_PLOT_HAS_NOT_COAST		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
REQUIRES_PLOT_HAS_COAST		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
REQUIRES_PLOT_HAS_DESERT		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
REQUIRES_PLOT_HAS_DESERT_HILLS		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
REQUIRES_PLOT_HAS_TUNDRA		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
REQUIRES_PLOT_HAS_TUNDRA_HILLS		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
REQUIRES_TERRAIN_OCEAN		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
REQUIRES_TERRAIN_COAST		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
PLOT_IS_GRASS_HILLS_TERRAIN_REQUIREMENT		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
PLOT_IS_PLAINS_HILLS_TERRAIN_REQUIREMENT	REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
PLOT_IS_TUNDRA_HILLS_TERRAIN_REQUIREMENT	REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
PLOT_IS_DESERT_HILLS_TERRAIN_REQUIREMENT	REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
PLOT_IS_SNOW_HILLS_TERRAIN_REQUIREMENT		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
REQUIRES_PLOT_HAS_SHALLOW_WATER		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
REQUIRES_PLOT_DESERT		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
REQUIRES_PLOT_HAS_SNOW		REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES
But for example with Petra Firaxis moved that to REQUIREMENT_PLOT_TERRAIN_CLASS_MATCHES but left the previous REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES with REQUIRES_PLOT_HAS_DESERT and REQUIRES_PLOT_HAS_DESERT_HILLS in the database for mod and other compatibility.

REQUIRES_PLOT_HAS_NOT_COAST uses the Boolean Inverse column to reverse the logic of REQUIRES_PLOT_HAS_COAST
 
  • Like
Reactions: cvb
I think, I'm done now with yields ... but have a final question: I searched the forum for TechModifiers without finding any, just to be sure: that would be their name ... not TechnoModifiers etc. :crazyeye:
Code:
INSERT INTO TechModifiers (TechType, ModifierId)
VALUES ("TECH_CELESTIAL_NAVIGATION", "NORMALISE_PLANTATIONS_JJ");

INSERT INTO Modifiers (ModifierId, ModifierType, OwnerRequirementSetId, SubjectRequirementSetId)
VALUES ("NORMALISE_PLANTATIONS_JJ", "MODIFIER_PLAYER_ADJUST_PLOT_YIELD", "PLAYER_IS_HUMAN", "PLOT_REQUIREMENTS_JJ");

INSERT INTO ModifierArguments (ModifierId, Name, Value)
VALUES ("NORMALISE_PLANTATIONS_JJ", "YieldType", "YIELD_FOOD"),
       ("NORMALISE_PLANTATIONS_JJ", "Amount", 1);

INSERT INTO RequirementSets (RequirementSetId, RequirementSetType)
VALUES ("PLOT_REQUIREMENTS_JJ", "REQUIREMENTSET_TEST_ANY");

INSERT INTO RequirementSetRequirements (RequirementSetId, RequirementId)
VALUES ("PLOT_REQUIREMENTS_JJ", "PLOT_IS_CITRUS_JJ"),
       ("PLOT_REQUIREMENTS_JJ", "PLOT_IS_SPICES_JJ"),
       ("PLOT_REQUIREMENTS_JJ", "PLOT_IS_SUGAR_JJ");

INSERT INTO Requirements (RequirementId, RequirementType)
VALUES ("PLOT_IS_CITRUS_JJ", "REQUIREMENT_PLOT_RESOURCE_TYPE_MATCHES"),
       ("PLOT_IS_SPICES_JJ", "REQUIREMENT_PLOT_RESOURCE_TYPE_MATCHES"),
       ("PLOT_IS_SUGAR_JJ", "REQUIREMENT_PLOT_RESOURCE_TYPE_MATCHES");

INSERT INTO RequirementArguments (RequirementId, Name, Value)
VALUES ("PLOT_IS_CITRUS_JJ", "ResourceType", "RESOURCE_CITRUS"),
       ("PLOT_IS_SPICES_JJ", "ResourceType", "RESOURCE_SPICES"),
       ("PLOT_IS_SUGAR_JJ", "ResourceType", "RESOURCE_SUGAR");
 
<TechnologyModifiers>

It's best to download an SQLite database viewer program and open the game's database file directly
\Documents\My Games\Sid Meier's Civilization VI\Cache\DebugGameplay.sqlite
Or to examine the database Schema definitions found at:
C:\Program Files (x86)\Steam\steamapps\common\Sid Meier's Civilization VI\Base\Assets\Gameplay\Data\Schema/01_GameplaySchema.sql
C:\Program Files (x86)\Steam\steamapps\common\Sid Meier's Civilization VI\DLC\Expansion1\Data/Expansion1_Schema.sql
C:\Program Files (x86)\Steam\steamapps\common\Sid Meier's Civilization VI\DLC\Expansion2\Data/Expansion2_Schema.sql
to find a table-name and the correct Columns and argument-types for each table.
 
  • Like
Reactions: cvb
Thanks a lot for your great help! I'll use those means then ...


I fooled myself:

GameEvents.PlayerCanResearchCivic ( PlayerID, CivicType )
GameEvents.PlayerCanResearchTech ( PlayerID, TechType )

INSERT INTO ModifierArguments (ModifierId, Name, Value)
VALUES ('MODIFIER_LEADER_HAN_WUDI_EARLY_TER_EXP', 'CivicType', 'CIVIC_EARLY_EMPIRE');
INSERT INTO ModifierArguments (ModifierId, Name, Value)
VALUES ("GREATPERSON_MATHTECHBOOST", "TechType", "TECH_MATHEMATICS"),

BUT:

<CivicModifiers>
<Row>
<CivicType>CIVIC_MYSTICISM</CivicType>
<ModifierId>CIVIC_AWARD_ONE_INFLUENCE_TOKEN</ModifierId>
</Row>
</CivicModifiers>

<GameData>
<TechnologyModifiers>
<Update>
<Where TechnologyType="TECH_MATHEMATICS" ModifierId="MATHEMATICS_ADJUST_SEA_MOVEMENT" />
<Set TechnologyType="TECH_MINING" />
</Update>
</TechnologyModifiers>
</GameData>

FOREIGN KEY (PrereqCivic) REFERENCES Civics(CivicType) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (PrereqTech) REFERENCES Technologies(TechnologyType) ON DELETE CASCADE ON UPDATE CASCADE,

.
 
First:
  • In lua argument names are just placeholders. The game passes Index # data or other ID # data for certain types of information in a given order for a particular Event or GameEvent hook
  • Documentation found on the internet for the argument data any lua hook passes to functions assigned to it is merely showing the sort of information being passed for the 1st, 2nd, 3rd, etc. arguments and using a convention for labelling these argument data-types. The names of the arguments shown in anyone's documentation has no actual functional reality.
  • We could just as well refer to the two GameEvents you mentioned as being
    Code:
    GameEvents.PlayerCanResearchCivic ( Hamburger, Cheeseburger )
    GameEvents.PlayerCanResearchTech ( Hamburger, Cheeseburger )
    This would be as accurate as anything shown on the internet, but it would be confusing. However, so long as we use these same argument designations consistently throughout the code of an lua script, the code will work just fine.
  • You cannot use anything you see in an lua script or documentation on lua code within Database Operations (ie, XML or SQL)
Second:
  • 'Name' arguments used in ModiferArguments and RequirementArguments have no actual relation to what is required as Column names within any given table(s)
  • Firaxis has specially and specifically coded into the game's DLL engine what the 'Name' argument values are and what they do, but none of the 'Name' argument values has anything at all to do with the database tables and columns used throughout the rest of the Database. They only seem to. This is because Firaxis with Civ6 have been very careful to make the arguments used for 'Name' both logical and consistent, and to use 'Name' arguments that are intuitive.
    • They could have been mean boogers and used 'Name' arguments such as '1', '2', '3', '4'.
  • The actual database definitions for what tables require must be used, not what is usable in tables ModiferArguments and RequirementArguments.
  • Hence why I advised you to refer always to the SQL Database DebugGameplay.sqlite file or the Schema definition files.
Firaxis has also generally shortened the amount of typing need to make code by pretty consistently calling some columns such things as 'PrereqTech' instead of 'PrerequisiteTechnologyType'. But a quick examination of the Technologies XML file in the Vanilla game folder shows that Techs are defined by a column called 'TechnologyType' and not by a column called 'Tech' or 'TechType' and that the table itself is called <Technologies> rather than <Techs>.
 
Last edited:
Back
Top Bottom