Really Stuck on Civ Trait!

Also, I checked out the Database Log, and it still has some errors, but I can't figure out what they are, given that the Mod is working:

[4022135.925] [Localization]: Validating Foreign Key Constraints...
[4022135.925] [Localization]: Passed Validation.
[4022135.936] [Configuration]: Validating Foreign Key Constraints...
[4022135.936] [Configuration]: Passed Validation.
[4022153.154] [FullTextSearch]: Initializing FullTextSearch
[4022155.060] [Gameplay]: Validating Foreign Key Constraints...
[4022155.074] [Gameplay]: Passed Validation.
[4022157.211] [Configuration] ERROR: no such table: Types
[4022157.257] [Configuration]: Validating Foreign Key Constraints...
[4022157.257] [Configuration]: Passed Validation.
[4022178.101] [FullTextSearch]: FTS - Creating Context
[4022193.621] [Configuration] ERROR: no such table: Types
[4022193.621] [Configuration]: Validating Foreign Key Constraints...
[4022193.621] [Configuration]: Passed Validation.
[4022195.177] [Gameplay] ERROR: NOT NULL constraint failed: Buildings.Name
[4022195.177] [Gameplay] ERROR: NOT NULL constraint failed: Buildings.Name
[4022195.209] [Gameplay]: Validating Foreign Key Constraints...
[4022195.225] [Gameplay]: Passed Validation.
[4022211.904] [FullTextSearch]: FTS - Creating Context
[4022213.077] [FullTextSearch]: FTS - Creating Context
[4022216.320] [FullTextSearch]: FTS - Creating Context
[4022463.244] [FullTextSearch]: FullTextSearch - Shutting down
 
Heh :) My pleasure! It was a neat puzzle to solve. I actually also created a LUA implementation of this mechanic that I find far more elegant (and I instinctively feel that it is more robust, though both of them work without hiccups so far). If you want to see it, I posted an earlier version in my own thread here. Once I finesse it a bit more, I'll post it here as a completed mod. About 85% of it is LUA, and it terminates in an XML implementation (also through a dummy building with an attached modifier, as I could not for the life of me figure out how to create unique GPs instead of generic GP units using LUA. And I've seen no solutions from anyone else so far. This may be either an unfinished segment of the LUA shell or an undisclosed method that no one can figure out). But I do like the LUA one better.

And yes, I guess you could call it the "Dummy Building" method, but it is an XML adaptation of LeeS' LUA functionality. Not that I followed any specific example, just the logic of it. The way the Requirements and Modifiers/Collection/Effects (together with the arguments for each) are set up in Civ 6 is atrocious. Like a straitjacket. So it forces one to invent somewhat unsightly chimeras. But they work, and there are ways of limiting the ugly optics, so I can't complain! :)

As for the LocalizedText ... here is what I have in my code above:

INSERT INTO Traits (TraitType, Name, Description) VALUES
('TRAIT_BUILDING_GP_GENERATOR', 'Trait Generating GPs', 'Trait that enables GP generation upon certain conditions being reached');

This is somewhat inelegant, but it gets the information across without using the LocalizedText table. Name is "Trait Generating GPs" and Description is "Trait that enables GP generation upon certain conditions being reached." I did this as a shortcut, and you don't have take it as well. I just can't be bothered with descriptions most of the time :).

Now, it really does not matter what values you give each of the TraitType, Name, Description columns here, but you have to keep it consistent throughout the code. So, if you want to use:

TRAIT_CIVILIZATION_ENGLAND_2 as a TraitType

you will have change the value I used throughout the code -- TRAIT_BUILDING_GP_GENERATOR (TraitType) -- to TRAIT_CIVILIZATION_ENGLAND_2 everywhere. Make sure you catch all instances. If you leave even one unchanged, the code won't work. However, if you don't care what the TraitType is (and you really shouldn't, as you would never see this value reflected in-game), then just change Name and Description. You can use the ones you originally had:

LOC_TRAIT_CIVILIZATION_ENGLAND_2_NAME -- LOC_TRAIT_CIVILIZATION_ENGLAND_2_DESC

So, use this statement instead of the one I had:

INSERT INTO Traits (TraitType, Name, Description) VALUES
('TRAIT_BUILDING_GP_GENERATOR', 'LOC_TRAIT_CIVILIZATION_ENGLAND_2_NAME', 'LOC_TRAIT_CIVILIZATION_ENGLAND_2_DESC');

Now, the next step is to correlate the values correctly with the LocalizedText table. In LocalizationDatabase_Schema.sql, the table is implemented with the following statement:

CREATE TABLE LocalizedText( 'Language' TEXT NOT NULL,
'Tag' TEXT NOT NULL,
'Text' TEXT,
'Gender' TEXT,
'Plurality' TEXT,
PRIMARY KEY (Language, Tag));

You had (Tag, Language, Text) above. You should have, instead:

INSERT INTO LocalizedText (Language, Tag, Text, Gender, Plurality) VALUES
('en_US', 'LOC_TRAIT_CIVILIZATION_ENGLAND_2_NAME', 'INSERT YOUR TEXT FOR THE NAME OF THE TRAIT HERE (Regular capitalization. It's just text.)', NULL, NULL);

and

INSERT INTO LocalizedText (Language, Tag, Text, Gender, Plurality) VALUES
('en_US', 'LOC_TRAIT_CIVILIZATION_ENGLAND_2_DESC', 'INSERT YOUR DESCRIPTION FOR THE TRAIT HERE (Regular capitalization. It's just text.)', NULL, NULL);

Make sure to remember the ' ' and a ; at the end of each individual statement (but use a comma instead to separate individual sets of values inserted with a single statement).

If you err in the syntax or forget to change the values in the NAME and DESCRIPTION columns to match the value you are using in the TAG column in LocalizedText, you'll get the result you describe above. Technically, however, what you use for and do with the NAME and DESCRIPTION columns has no effect on functionality. It's just optics. But yes, see above.
 
Thanks for that. I put the code in and it works, but only the Civ Loading Screen, not on the Selection Screen. There is no text shown when selecting the Civ on the Menu. How do I change this?
 
Ah, ok, as for your Database errors. I know why these ones crop up:

[4022195.177] [Gameplay] ERROR: NOT NULL constraint failed: Buildings.Name
[4022195.177] [Gameplay] ERROR: NOT NULL constraint failed: Buildings.Name

I keep forgetting to check whether the value in a Column can be NULL, In the case of the Buildings.Name column, it cannot. So, forget trying to hide the dummy buildings by omitting the Name value. Use these statements instead for the buildings:

INSERT INTO Buildings (BuildingType, Name, Description, PrereqTech, PrereqDistrict, Cost, MustPurchase, TraitType) VALUES
('BUILDING_GP_GENERATOR', ' ', NULL, 'TECH_INDUSTRIALIZATION', 'DISTRICT_INDUSTRIAL_ZONE', 1, 1, "TRAIT_BUILDING_GP_GENERATOR");

INSERT INTO CivilopediaPageExcludes (SectionId, PageId) VALUES ('BUILDINGS', 'BUILDING_GP_GENERATOR');

INSERT INTO Buildings (BuildingType, Name, Description, PrereqDistrict, Cost, MustPurchase) VALUES
('BUILDING_ANTI_GP_GENERATOR', ' ', NULL, NULL, 'DISTRICT_INDUSTRIAL_ZONE', 1, 1);

INSERT INTO CivilopediaPageExcludes (SectionId, PageId) VALUES ('BUILDINGS', 'BUILDING_ANTI_GP_GENERATOR');

Or you can use actual text for Buildings.Name, such as 'BUILDING_GP_GENERATOR_NAME' and then define it as NULL when you do an INSERT statement into LocalizedText table. There is no NOT NULL constraint there, so it should work. Or even give these building some kind of intelligible name, if you wish. It's just optics, after all.

As for this error, I have no idea...

[4022193.621] [Configuration] ERROR: no such table: Types

This comes from the Configuration (Maps, Difficulties, Game Setup) wing, and nothing in my code touches that part of the game. It must be another mod or, perhaps, something in your own mod that you've coded. There is indeed no such table as Types in the Configuration Schema. But what part of your code is causing the error to manifest... you'll to go digging. Have you created any rulesets?

At least the Requirements error seems to be gone! That's good ... :)
 
I am not sure why it works for the Loading and not for the Selection screen. Do you maybe have too many traits attached to England? Actually, now that I think of it, I am not sure that the Selection screen has ever updated for me when I've change player traits. Maybe it's harcoded? If there is a way to enforce the change, and if this way does not lie through XML, then LUA UI must be involved, and that's far too complicated for this late at night ;). Maybe it is harcoded. If it is, then you can't change it. Dunno...
 
The ONLY reason you need dummy buildings in the first place is to determine whether or not the city built the industrial district before or after getting the tech. If you didn't have the situation where a city could build an industrial district before that tech and not receive a GP (even after researching that tech), then you could do what you want in literally 2 modifiers at most. The modifiers system is incredibly robust, and dummy buildings are rarely required. They really are only needed to track the state or number of things, since you can't check whether an entity has a given modifier via requirements. In fact, look here for a great guide on modifiers: https://nycholusv.com/guides/using-modifiers/
 
I am by now quite comfortable with the modifiers system, which is the reason I finally had to resort to a dummy building, after trying a number of approaches. Otherwise, I'd still be trying to find a modifier/requirement set, quite hopelessly, to realize the effect that I was able to achieve. There may well be some ingenious way to avoid a dummy building, but I doubt it. I tried setting up a new dynamic modifier (modifier/collection/effect), to no avail. There is is simply no way to do the above in the straitjacket system of modifiers. In LUA, however, that's a different story. In LUA, the problem is that not all required functions have been implemented (there is no function to generate a unique GP, which is why a dummy building is still necessary). Otherwise, LUA is far more robust, though more complex.

In fact, the reason I needed to use the ACTIVE dummy building did not have to do with checking whether or not the city built the industrial district before or after getting the tech. To check for that I used the ANTI dummy building (to prevent the placement of the ACTIVE dummy building once research of the required tech has been completed). The only stumbling block I had in the way of doing all of the above exclusively in modifiers was my inability to make:

<Row Type="REQUIREMENT_CIV_TYPE_MATCHES" Kind="KIND_REQUIREMENT"/>

work. If that had worked, the solution would have been clean and neat. Alas...
 
In LUA, however, that's a different story. In LUA, the problem is that not all required functions have been implemented (there is no function to generate a unique GP, which is why a dummy building is still necessary). Otherwise, LUA is far more robust, though more complex.

Yeah, I think I heard that problem before about lua, specifically that function. You could, though, use lua to give a dummy building, I presume. I was actually trying to build out the desired effect without needing the dummy buildings, but you do need at least the anti-dummy building to keep track of the districts built before the tech was acquired. Could you not, though, just use the same modifier effect (with possibly a new dynamic modifier) to grant a gp, without needing the active dummy building? Or is it actually necessary for some reason? Does the owner of the modifier have to be the building, or could the owner just be the city or district?
 
That's what I've done with the LUA implementation. After all the checks are complete (Required Civ, Required Tech, Required District), a dummy building is placed in the city center, with a modifier attached to generate a GP, and then that building is removed. There is no need for an anti-dummy building that way, and there is no need to have checks against a district created before the tech is reached getting the dummy building when the tech is researched. The implementation is cleaner.

The reason why a dummy building is required is that the modifier that grants GPs appears to need a trigger of some kind. It needs something to happen before it is activated. In the base game, for Stonehenge, the trigger is a Building (Wonder). However, Stonehenge has no requirement of a Civilization Type or a Technology Type. So, it's simple there. If you attach the modifier to a District, then you lose the ability to check for Civilization Type, though you can still check for Technology Type. Unless the district is a unique replacement for a basic game district.

The reason you need a dummy building is SOLELY to check for Civilization Type. That's where the Civilization Trait comes in. You tie the dummy building to a Civilization Trait, and, voila, you have your check on Civilization Type. If you wanted to avoid a dummy building then you would need a SubjectRequirementSetId that checks for the Civilization Type of the subject of the modifier. However, the only Requirement that I could find -- REQUIREMENT_CIV_TYPE_MATCHES -- does not work. Or, alternatively, I don't know how to make it work, or it works in mysterious ways that have nothing to do with what we understand to be a Civilization Type (i.e. "CIVILIZATION_ENGLAND", etc.). If this Requirement functioned, then I could easily have avoided the dummy building (and the anti-dummy building, for that matter). As it stands... ce la vie...
 
Ah, I see. Thanks for the info. But for that requirement you mentioned, maybe it refers to the StartingCivilizationLevelType, since City States are considered Minor civs, but are still implemented under the same table. It might check whether a civ is a full civ or a city state :/
 
Yup, that's what I think it might be, but I haven't checked it further. If I recall correctly, StartingCivilizationLevelType (or checking for Minor/Tribe level civs) is already checked by a different Requirement, but it may well be that this one does the same thing. All I know is that REQUIREMENT_CIV_TYPE_MATCHES is not used anywhere else in the base game, and, as is often the case in these instances, does not appear to work correctly. Cheers!
 
Does anyone know how to insert text to show up on the Civ selection screen other than the manner in which I've done it? What I've done so far is I've disabled England's Trait by:

DELETE FROM CivilizationTraits WHERE TraitType = 'TRAIT_CIVILIZATION_DOUBLE_ARCHAEOLOGY_SLOTS';

and this seems to work. I am then able to change the text on the Civ selection screen by changing Localized Text for TRAIT_CIVILIZATION_DOUBLE..... and this works; but I then have to add another INSERT OR REPLACE INTO LocalizedText .... for TRAIT_BUILDING_GP_GENERATOR.... for it to appear on the Civ loading screen. However, the latter doesn't work when there are additional units added like in MOAR Units. I think this has something to do with 'PlayerItems' or 'SortIndex'???

I have tried UPDATE Players WHERE CivilizationAbilityName = ..... SET .... but this doesn't seem to work.

Anyone have any idea on how to do this (if I haven't confused you already)?
 
Hey, @Cagarustus -- you can delete the previous awkward and cumbersome (dummy building) method I supplied earlier. After doing some Lua checking of how Modifiers & Requirements work, and working through the problem again, I have come up with a far more elegant, and -- this time -- entirely direct method of your GP Generation trait. The code below will check directly for:

(1) whether the player has the required technology; and,

(2) whether the city has the required district.
The new Trait is entirely self-contained and requires no external support or subsystems relating to districts or dummy buildings, etc. It's all done through a clean single Modifier with two simple Requirements. The dummy buildings were bothering me, and I am glad to be rid of them.

Here you go:

Code:
-- GP GENERATION TRAIT
-- (1) Required Technology - Industrialization Technology (Owner Requirement - Checks Player Qualifications)
-- (2) Required Technology - District Industrial Zone (Subject Requirement - Checks City Qualifications)

INSERT INTO Types (Type, Kind) VALUES
('MODIFIER_PLAYER_CITIES_GRANT_GP_IN_CITY', 'KIND_MODIFIER'),
('TRAIT_GP_IN_QUALIFIED_CITY', 'KIND_TRAIT');

INSERT INTO DynamicModifiers (ModifierType, CollectionType, EffectType) VALUES
('MODIFIER_PLAYER_CITIES_GRANT_GP_IN_CITY', 'COLLECTION_PLAYER_CITIES', 'EFFECT_GRANT_GREAT_PERSON_CLASS_IN_CITY');

INSERT INTO Traits (TraitType, Name, Description) VALUES
('TRAIT_GP_IN_QUALIFIED_CITY', 'LOC_TRAIT_GP_IN_QUALIFIED_CITY_NAME', 'LOC_TRAIT_GP_IN_QUALIFIED_CITY_DESCRIPTION');

INSERT INTO CivilizationTraits (CivilizationType, TraitType) VALUES
('CIVILIZATION_ENGLAND', 'TRAIT_GP_IN_QUALIFIED_CITY');

INSERT INTO TraitModifiers (TraitType, ModifierId) VALUES
('TRAIT_GP_IN_QUALIFIED_CITY', 'GP_ENG_QUALIFIED_CITY_MODIFIER');

INSERT INTO Modifiers (ModifierId, ModifierType, RunOnce, Permanent, OwnerRequirementSetId, SubjectRequirementSetId) VALUES
('GP_ENG_QUALIFIED_CITY_MODIFIER', 'MODIFIER_PLAYER_CITIES_GRANT_GP_IN_CITY', 0, 1, 'PLAYER_HAS_REQUIRED_TECH_REQUIREMENTS', 'CITY_HAS_REQUIRED_DISTRICT_REQUIREMENTS');

INSERT INTO ModifierArguments (ModifierId, Name, Type, Value, Extra, SecondExtra) VALUES
('GP_ENG_QUALIFIED_CITY_MODIFIER', 'GreatPersonClassType', 'ARGTYPE_IDENTITY', 'GREAT_PERSON_CLASS_ENGINEER', NULL, NULL),
('GP_ENG_QUALIFIED_CITY_MODIFIER', 'Amount', 'ARGTYPE_IDENTITY', '1', NULL, NULL);

INSERT INTO RequirementSets (RequirementSetId, RequirementSetType) VALUES
('PLAYER_HAS_REQUIRED_TECH_REQUIREMENTS', 'REQUIREMENTSET_TEST_ALL'),
('CITY_HAS_REQUIRED_DISTRICT_REQUIREMENTS', 'REQUIREMENTSET_TEST_ALL');

INSERT INTO RequirementSetRequirements (RequirementSetId, RequirementId) VALUES
('PLAYER_HAS_REQUIRED_TECH_REQUIREMENTS', 'REQUIRES_REQUIRED_TECH'),
('CITY_HAS_REQUIRED_DISTRICT_REQUIREMENTS', 'REQUIRES_REQUIRED_DISTRICT');

INSERT INTO Requirements (RequirementId, RequirementType) VALUES
('REQUIRES_REQUIRED_TECH', 'REQUIREMENT_PLAYER_HAS_TECHNOLOGY'),
('REQUIRES_REQUIRED_DISTRICT', 'REQUIREMENT_CITY_HAS_DISTRICT');

INSERT INTO RequirementArguments (RequirementId, Name, Type, Value, Extra, SecondExtra) VALUES
('REQUIRES_REQUIRED_TECH', 'TechnologyType', 'ARGTYPE_IDENTITY', 'TECH_INDUSTRIALIZATION', NULL, NULL),
('REQUIRES_REQUIRED_DISTRICT', 'DistrictType', 'ARGTYPE_IDENTITY', 'DISTRICT_INDUSTRIAL_ZONE', NULL, NULL);

EDIT: NVM, I've tested it and it works just fine when the required district is built before the research of the required technology is complete. No GP is generated. Only when both conditions are satisfied at once does the GP generation trigger. This works, it seems. :)
 
Last edited:
Hey, thanks for that.

I stumbled on another Mod the other day: JFD's Nicholas II Alternative Leader for Russia, whose Trait is to grant a Great Engineer every time an Industrial Zone is built. Upon looking through the code, it turns out that there is a Modifier: MODIFIER_PLAYER_DISTRICT_CREATE UNIT, which JFD used.

I think that Modifier would be relatively simple to use with the Requirement.
 
Unfortunately, JFD's implementation won't help you for several reasons (as far as I understand his mod):

(1) the unit Russia gets upon construction of an Industrial Zone is a Military Engineer, not a Great Engineer;
(2) JFD does his implementation in part through Lua, not entirely XML (I took a quick look at his mod, and that's what I see, correct me if I am wrong). I don't know of a way in Lua to create a Unique Great Person, only the generic kind. My own Lua implementation terminates in XML to produce GPs;
(3) The MODIFIER_PLAYER_DISTRICT_CREATE_UNIT does not do what you want it to do:

(a) it can only create a regular unit, not a Unique GP;
(b) you can get apostles, trades, whatever, but not Great Engineers or Prophets.
But sure, feel free and give it a try. I just don't think it will give you what you are looking for. Here is the code, specifically:

Code:
--------------------------------------------------------------------------------------------------------------------------
-- Modifiers
--------------------------------------------------------------------------------------------------------------------------
INSERT INTO Modifiers 
        (ModifierId,                                                    ModifierType,                                                SubjectRequirementSetId)
VALUES    ('TRAIT_JFD_TRANS_SIBERIAN_RAILWAY_INDUSTRIAL_ZONE',            'MODIFIER_PLAYER_CITIES_ADJUST_DISTRICT_PRODUCTION',        null),
        ('TRAIT_JFD_TRANS_SIBERIAN_RAILWAY_INDUSTRIAL_ZONE_FAITH',        'MODIFIER_PLAYER_CITIES_ENABLE_BUILDING_FAITH_PURCHASE',    null),
        ('TRAIT_JFD_TRANS_SIBERIAN_RAILWAY_INDUSTRIAL_ZONE_ENGINEER',    'MODIFIER_PLAYER_DISTRICT_CREATE_UNIT',                        null);
--------------------------------------------------------------------------------------------------------------------------
-- ModifierArguments
--------------------------------------------------------------------------------------------------------------------------
INSERT INTO ModifierArguments
        (ModifierId,                                                    Name,                    Value,                                Extra,                Type)
VALUES    ('TRAIT_JFD_TRANS_SIBERIAN_RAILWAY_INDUSTRIAL_ZONE',            'Amount',                50,                                    null,                'ARGTYPE_IDENTITY'),
        ('TRAIT_JFD_TRANS_SIBERIAN_RAILWAY_INDUSTRIAL_ZONE',            'DistrictType',            'DISTRICT_INDUSTRIAL_ZONE',            null,                'ARGTYPE_IDENTITY'),
        ('TRAIT_JFD_TRANS_SIBERIAN_RAILWAY_INDUSTRIAL_ZONE_FAITH',        'DistrictType',            'DISTRICT_INDUSTRIAL_ZONE',            null,                'ARGTYPE_IDENTITY'),
        ('TRAIT_JFD_TRANS_SIBERIAN_RAILWAY_INDUSTRIAL_ZONE_ENGINEER',    'DistrictType',            'DISTRICT_INDUSTRIAL_ZONE',            null,                'ARGTYPE_IDENTITY'),
        ('TRAIT_JFD_TRANS_SIBERIAN_RAILWAY_INDUSTRIAL_ZONE_ENGINEER',    'UnitType',                'UNIT_MILITARY_ENGINEER',            null,                'ARGTYPE_IDENTITY');

The solution I gave you above is 100% tested and functional. Good luck.
 
Ah, I see. Makes sense. I overlooked the 'Military Engineer.' Got too carried away. Cheers!

BTW, I posted on another thread about giving my Scouts, Settlers and Builders extra movement, ignoring terrain costs etc. but I want them to apply only to me and not to the AI. Having a look at the Modifiers table, I think I need to use: MODIFIER_PLAYER_UNITS_GRANT_ABILITY; ABILITY_RELIGIOUS_IGNORE_TERRAIN (the Missionary Zeal belief) and 'MODIFIER_PLAYER_UNITS_ADJUST_MOVEMENT.

I could probably put down some code on my own, but I'm not sure if I'll need to use Requirements for Unit_Type_Matches or not; or if I use the TypeTags as is listed in the UnitAbility tables?
 
Back
Top Bottom